agnes/
store.rs

1/*!
2Data storage struct and implementation.
3
4[DataStore](struct.DataStore.html) represents and stores the data from a single data source.
5*/
6use std::fmt::Debug;
7use std::ops::Deref;
8use std::rc::Rc;
9
10#[cfg(feature = "serialize")]
11use serde::ser::{Serialize, Serializer};
12use typenum::uint::UTerm;
13
14use access::{DataIndex, NRows};
15use cons::*;
16use error;
17use field::{FieldData, Value};
18use fieldlist::{FieldCons, FieldPayloadCons, FieldSchema};
19use frame::{DataFrame, SimpleFrameFields};
20use label::*;
21use select::{FieldSelect, SelectFieldByLabel};
22use view::{DataView, FrameLookupCons, ViewFrameCons};
23
24/// Local `Rc` wrapper type for [FieldData](../field/struct.FieldData.html) objects.
25#[derive(Debug, Hash, PartialEq, Eq)]
26pub struct DataRef<DType>(pub Rc<FieldData<DType>>);
27
28impl<DType> DataRef<DType> {
29    fn new(field: FieldData<DType>) -> DataRef<DType> {
30        DataRef(Rc::new(field))
31    }
32}
33
34impl<DType> Clone for DataRef<DType> {
35    fn clone(&self) -> DataRef<DType> {
36        DataRef(Rc::clone(&self.0))
37    }
38}
39
40impl<T> Deref for DataRef<T> {
41    type Target = FieldData<T>;
42
43    fn deref(&self) -> &FieldData<T> {
44        &self.0.deref()
45    }
46}
47
48impl<T> From<FieldData<T>> for DataRef<T> {
49    fn from(orig: FieldData<T>) -> DataRef<T> {
50        DataRef(Rc::new(orig))
51    }
52}
53
54impl<T> DataIndex for DataRef<T>
55where
56    FieldData<T>: DataIndex<DType = T>,
57    T: Debug,
58{
59    type DType = T;
60
61    fn get_datum(&self, idx: usize) -> error::Result<Value<&T>> {
62        <FieldData<T> as DataIndex>::get_datum(&self.0, idx)
63    }
64    fn len(&self) -> usize {
65        <FieldData<T> as DataIndex>::len(&self.0)
66    }
67}
68
69#[cfg(feature = "serialize")]
70impl<T> Serialize for DataRef<T>
71where
72    T: Serialize,
73{
74    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75    where
76        S: Serializer,
77    {
78        self.0.serialize(serializer)
79    }
80}
81
82/// Type alias for main data store cons-list. Each `head` contains label and data type information
83/// along with a [DataRef(struct.DataRef.html)] reference to the data for this field.
84pub type StorageCons<Label, DType, Tail> = FieldPayloadCons<Label, DType, DataRef<DType>, Tail>;
85
86/// Primary `agnes` data storage object. `Fields` is a [FieldCons](../fieldlist/type.FieldCons.html)
87/// cons-list which implements [AssocStorage](trait.AssocStorage.html); the `DataStore` contains
88/// this associated storage structure.
89#[derive(Debug)]
90pub struct DataStore<Fields: AssocStorage> {
91    data: Fields::Storage,
92}
93
94/// Provide an associated [StorageCons](type.StorageCons.html) cons-list with `Self`.
95pub trait AssocStorage {
96    /// Associated [StorageCons](type.StorageCons.html) cons-list.
97    type Storage: Debug;
98}
99impl<Label, DType, Tail> AssocStorage for FieldCons<Label, DType, Tail>
100where
101    Tail: AssocStorage,
102    Label: Debug,
103    DType: Debug,
104{
105    type Storage = StorageCons<Label, DType, Tail::Storage>;
106}
107impl AssocStorage for Nil {
108    type Storage = Nil;
109}
110
111impl<Fields> DataStore<Fields>
112where
113    Fields: AssocStorage,
114{
115    /// Generate and return an empty data store
116    pub fn empty() -> DataStore<Nil> {
117        DataStore { data: Nil }
118    }
119}
120
121impl<Fields> NRows for DataStore<Fields>
122where
123    Fields: AssocStorage,
124    Fields::Storage: NRows,
125{
126    fn nrows(&self) -> usize {
127        self.data.nrows()
128    }
129}
130
131/// Type alias for a reference to a [FieldData](../field/struct.FieldData.html) along with label
132/// and data type annotation.
133pub type NewFieldStorage<NewLabel, NewDType> =
134    Labeled<NewLabel, TypedValue<NewDType, DataRef<NewDType>>>;
135
136macro_rules! make_add_field {
137    (
138        $(#[$add_trait_doc:meta])* trait $add_trait:tt;
139        $(#[$add_fn_doc:meta])* fn $add_fn:tt;
140
141        $(#[$add_valiter_trait_doc:meta])* trait $add_valiter_trait:tt;
142        $(#[$add_valiter_fn_doc:meta])* fn $add_valiter_fn:tt;
143
144        $(#[$add_iter_trait_doc:meta])* trait $add_iter_trait:tt;
145        $(#[$add_iter_fn_doc:meta])* fn $add_iter_fn:tt;
146
147        $(#[$add_cloned_valiter_trait_doc:meta])* trait $add_cloned_valiter_trait:tt;
148        $(#[$add_cloned_valiter_fn_doc:meta])* fn $add_cloned_valiter_fn:tt;
149
150        $(#[$add_cloned_iter_trait_doc:meta])* trait $add_cloned_iter_trait:tt;
151        $(#[$add_cloned_iter_fn_doc:meta])* fn $add_cloned_iter_fn:tt;
152
153        $(#[$add_empty_trait_doc:meta])* trait $add_empty_trait:tt;
154        $(#[$add_empty_fn_doc:meta])* fn $add_empty_fn:tt;
155
156        $push_trait:tt $push_fn:tt $pushed_alias:tt
157    ) => {
158        /// Type alias for the output of applying $push_fn to previous fields.
159        pub type $pushed_alias<PrevFields, NewLabel, NewDType> =
160            <PrevFields as $push_trait<FieldSchema<NewLabel, NewDType>>>::Output;
161
162        $(#[$add_trait_doc])*
163        pub trait $add_trait<NewLabel, NewDType> {
164            /// [FieldCons](../fieldlist/type.FieldCons.html) cons-list after adding field.
165            type OutputFields: AssocStorage;
166
167            $(#[$add_fn_doc])*
168            fn $add_fn(self, data: FieldData<NewDType>) -> DataStore<Self::OutputFields>;
169        }
170
171        impl<PrevFields, NewLabel, NewDType> $add_trait<NewLabel, NewDType>
172            for DataStore<PrevFields>
173        where
174            PrevFields: AssocStorage + $push_trait<FieldSchema<NewLabel, NewDType>>,
175            $pushed_alias<PrevFields, NewLabel, NewDType>: AssocStorage,
176            PrevFields::Storage: $push_trait<
177                NewFieldStorage<NewLabel, NewDType>,
178                Output = <$pushed_alias<PrevFields, NewLabel, NewDType> as AssocStorage>::Storage,
179            >,
180            NewLabel: Debug,
181            NewDType: Debug,
182        {
183            type OutputFields = $pushed_alias<PrevFields, NewLabel, NewDType>;
184
185            fn $add_fn(self, data: FieldData<NewDType>) -> DataStore<Self::OutputFields> {
186                DataStore {
187                    data: self
188                        .data
189                        .$push_fn(TypedValue::from(DataRef::new(data)).into()),
190                }
191            }
192        }
193
194        $(#[$add_valiter_trait_doc])*
195        pub trait $add_valiter_trait<NewLabel, NewDType> {
196            /// [FieldCons](../fieldlist/type.FieldCons.html) cons-list after adding field.
197            type OutputFields: AssocStorage;
198
199            $(#[$add_valiter_fn_doc])*
200            fn $add_valiter_fn<IntoIter, Iter>(
201                self,
202                iter: IntoIter,
203            ) -> DataStore<Self::OutputFields>
204            where
205                Iter: Iterator<Item = Value<NewDType>>,
206                IntoIter: IntoIterator<IntoIter = Iter, Item = Value<NewDType>>;
207        }
208        impl<PrevFields, NewLabel, NewDType> $add_valiter_trait<NewLabel, NewDType>
209            for DataStore<PrevFields>
210        where
211            PrevFields: AssocStorage + $push_trait<FieldSchema<NewLabel, NewDType>>,
212            $pushed_alias<PrevFields, NewLabel, NewDType>: AssocStorage,
213            PrevFields::Storage: $push_trait<
214                NewFieldStorage<NewLabel, NewDType>,
215                Output = <$pushed_alias<PrevFields, NewLabel, NewDType> as AssocStorage>::Storage,
216            >,
217            NewLabel: Debug,
218            NewDType: Default + Debug,
219        {
220            type OutputFields = $pushed_alias<PrevFields, NewLabel, NewDType>;
221
222            fn $add_valiter_fn<IntoIter, Iter>(
223                self,
224                iter: IntoIter,
225            ) -> DataStore<Self::OutputFields>
226            where
227                Iter: Iterator<Item = Value<NewDType>>,
228                IntoIter: IntoIterator<IntoIter = Iter, Item = Value<NewDType>>,
229            {
230                DataStore {
231                    data: self.data.$push_fn(
232                        TypedValue::from(DataRef::new(
233                            iter.into_iter().collect::<FieldData<NewDType>>(),
234                        ))
235                        .into(),
236                    ),
237                }
238            }
239        }
240
241        $(#[$add_iter_trait_doc])*
242        pub trait $add_iter_trait<NewLabel, NewDType> {
243            /// [FieldCons](../fieldlist/type.FieldCons.html) cons-list after adding field.
244            type OutputFields: AssocStorage;
245
246            $(#[$add_iter_fn_doc])*
247            fn $add_iter_fn<IntoIter, Iter>(self, iter: IntoIter) -> DataStore<Self::OutputFields>
248            where
249                Iter: Iterator<Item = NewDType>,
250                IntoIter: IntoIterator<IntoIter = Iter, Item = NewDType>;
251        }
252        impl<PrevFields, NewLabel, NewDType> $add_iter_trait<NewLabel, NewDType>
253            for DataStore<PrevFields>
254        where
255            PrevFields: AssocStorage + $push_trait<FieldSchema<NewLabel, NewDType>>,
256            $pushed_alias<PrevFields, NewLabel, NewDType>: AssocStorage,
257            PrevFields::Storage: $push_trait<
258                NewFieldStorage<NewLabel, NewDType>,
259                Output = <$pushed_alias<PrevFields, NewLabel, NewDType> as AssocStorage>::Storage,
260            >,
261            NewLabel: Debug,
262            NewDType: Debug,
263        {
264            type OutputFields = $pushed_alias<PrevFields, NewLabel, NewDType>;
265
266            fn $add_iter_fn<IntoIter, Iter>(self, iter: IntoIter) -> DataStore<Self::OutputFields>
267            where
268                Iter: Iterator<Item = NewDType>,
269                IntoIter: IntoIterator<IntoIter = Iter, Item = NewDType>,
270            {
271                DataStore {
272                    data: self.data.$push_fn(
273                        TypedValue::from(DataRef::new(
274                            iter.into_iter().collect::<FieldData<NewDType>>(),
275                        ))
276                        .into(),
277                    ),
278                }
279            }
280        }
281
282        $(#[$add_cloned_valiter_trait_doc])*
283        pub trait $add_cloned_valiter_trait<NewLabel, NewDType> {
284            /// [FieldCons](../fieldlist/type.FieldCons.html) cons-list after adding field.
285            type OutputFields: AssocStorage;
286
287            $(#[$add_cloned_valiter_fn_doc])*
288            fn $add_cloned_valiter_fn<'a, IntoIter, Iter>(
289                self,
290                iter: IntoIter,
291            ) -> DataStore<Self::OutputFields>
292            where
293                Iter: Iterator<Item = Value<&'a NewDType>>,
294                IntoIter: IntoIterator<IntoIter = Iter, Item = Value<&'a NewDType>>,
295                NewDType: 'a;
296        }
297        impl<PrevFields, NewLabel, NewDType> $add_cloned_valiter_trait<NewLabel, NewDType>
298            for DataStore<PrevFields>
299        where
300            PrevFields: AssocStorage + $push_trait<FieldSchema<NewLabel, NewDType>>,
301            $pushed_alias<PrevFields, NewLabel, NewDType>: AssocStorage,
302            PrevFields::Storage: $push_trait<
303                NewFieldStorage<NewLabel, NewDType>,
304                Output = <$pushed_alias<PrevFields, NewLabel, NewDType> as AssocStorage>::Storage,
305            >,
306            NewLabel: Debug,
307            NewDType: Default + Clone + Debug,
308        {
309            type OutputFields = $pushed_alias<PrevFields, NewLabel, NewDType>;
310
311            fn $add_cloned_valiter_fn<'a, IntoIter, Iter>(
312                self,
313                iter: IntoIter,
314            ) -> DataStore<Self::OutputFields>
315            where
316                Iter: Iterator<Item = Value<&'a NewDType>>,
317                IntoIter: IntoIterator<IntoIter = Iter, Item = Value<&'a NewDType>>,
318                NewDType: 'a,
319            {
320                DataStore {
321                    data: self.data.$push_fn(
322                        TypedValue::from(DataRef::new(
323                            iter.into_iter()
324                                .map(|x| x.clone())
325                                .collect::<FieldData<NewDType>>(),
326                        ))
327                        .into(),
328                    ),
329                }
330            }
331        }
332
333        $(#[$add_cloned_iter_trait_doc])*
334        pub trait $add_cloned_iter_trait<NewLabel, NewDType> {
335            /// [FieldCons](../fieldlist/type.FieldCons.html) cons-list after adding field.
336            type OutputFields: AssocStorage;
337
338            $(#[$add_cloned_iter_fn_doc])*
339            fn $add_cloned_iter_fn<'a, IntoIter, Iter>(
340                self,
341                iter: IntoIter,
342            ) -> DataStore<Self::OutputFields>
343            where
344                Iter: Iterator<Item = &'a NewDType>,
345                IntoIter: IntoIterator<IntoIter = Iter, Item = &'a NewDType>,
346                NewDType: 'a;
347        }
348        impl<PrevFields, NewLabel, NewDType> $add_cloned_iter_trait<NewLabel, NewDType>
349            for DataStore<PrevFields>
350        where
351            PrevFields: AssocStorage + $push_trait<FieldSchema<NewLabel, NewDType>>,
352            $pushed_alias<PrevFields, NewLabel, NewDType>: AssocStorage,
353            PrevFields::Storage: $push_trait<
354                NewFieldStorage<NewLabel, NewDType>,
355                Output = <$pushed_alias<PrevFields, NewLabel, NewDType> as AssocStorage>::Storage,
356            >,
357            NewLabel: Debug,
358            NewDType: Clone + Debug,
359        {
360            type OutputFields = $pushed_alias<PrevFields, NewLabel, NewDType>;
361
362            fn $add_cloned_iter_fn<'a, IntoIter, Iter>(
363                self,
364                iter: IntoIter,
365            ) -> DataStore<Self::OutputFields>
366            where
367                Iter: Iterator<Item = &'a NewDType>,
368                IntoIter: IntoIterator<IntoIter = Iter, Item = &'a NewDType>,
369                NewDType: 'a,
370            {
371                DataStore {
372                    data: self.data.$push_fn(
373                        TypedValue::from(DataRef::new(
374                            iter.into_iter()
375                                .map(|x| x.clone())
376                                .collect::<FieldData<NewDType>>(),
377                        ))
378                        .into(),
379                    ),
380                }
381            }
382        }
383
384        $(#[$add_empty_trait_doc])*
385        pub trait $add_empty_trait<NewLabel, NewDType> {
386            /// [FieldCons](../fieldlist/type.FieldCons.html) cons-list after adding field.
387            type OutputFields: AssocStorage;
388
389            $(#[$add_empty_fn_doc])*
390            fn $add_empty_fn(self) -> DataStore<Self::OutputFields>;
391        }
392        impl<PrevFields, NewLabel, NewDType> $add_empty_trait<NewLabel, NewDType>
393            for DataStore<PrevFields>
394        where
395            PrevFields: AssocStorage + $push_trait<FieldSchema<NewLabel, NewDType>>,
396            $pushed_alias<PrevFields, NewLabel, NewDType>: AssocStorage,
397            PrevFields::Storage: $push_trait<
398                NewFieldStorage<NewLabel, NewDType>,
399                Output = <$pushed_alias<PrevFields, NewLabel, NewDType> as AssocStorage>::Storage,
400            >,
401            NewLabel: Debug,
402            NewDType: Debug,
403        {
404            type OutputFields = $pushed_alias<PrevFields, NewLabel, NewDType>;
405
406            fn $add_empty_fn(self) -> DataStore<Self::OutputFields> {
407                DataStore {
408                    data: self
409                        .data
410                        .$push_fn(TypedValue::from(DataRef::new(FieldData::default())).into()),
411                }
412            }
413        }
414
415        impl<PrevFields> DataStore<PrevFields>
416        where
417            PrevFields: AssocStorage,
418        {
419            $(#[$add_fn_doc])*
420            pub fn $add_fn<NewLabel, NewDType>(
421                self,
422                data: FieldData<NewDType>,
423            ) -> DataStore<<Self as $add_trait<NewLabel, NewDType>>::OutputFields>
424            where
425                Self: $add_trait<NewLabel, NewDType>,
426            {
427                $add_trait::$add_fn(self, data)
428            }
429
430            $(#[$add_valiter_fn_doc])*
431            pub fn $add_valiter_fn<NewLabel, NewDType, IntoIter, Iter>(
432                self,
433                iter: IntoIter,
434            ) -> DataStore<<Self as $add_valiter_trait<NewLabel, NewDType>>::OutputFields>
435            where
436                Iter: Iterator<Item = Value<NewDType>>,
437                IntoIter: IntoIterator<IntoIter = Iter, Item = Value<NewDType>>,
438                Self: $add_valiter_trait<NewLabel, NewDType>,
439            {
440                $add_valiter_trait::$add_valiter_fn(self, iter)
441            }
442
443            $(#[$add_iter_fn_doc])*
444            pub fn $add_iter_fn<NewLabel, NewDType, IntoIter, Iter>(
445                self,
446                iter: IntoIter,
447            ) -> DataStore<<Self as $add_iter_trait<NewLabel, NewDType>>::OutputFields>
448            where
449                Iter: Iterator<Item = NewDType>,
450                IntoIter: IntoIterator<IntoIter = Iter, Item = NewDType>,
451                Self: $add_iter_trait<NewLabel, NewDType>,
452            {
453                $add_iter_trait::$add_iter_fn(self, iter)
454            }
455
456            $(#[$add_cloned_valiter_fn_doc])*
457            pub fn $add_cloned_valiter_fn<'a, NewLabel, NewDType, IntoIter, Iter>(
458                self,
459                iter: IntoIter,
460            ) -> DataStore<<Self as $add_cloned_valiter_trait<NewLabel, NewDType>>::OutputFields>
461            where
462                Iter: Iterator<Item = Value<&'a NewDType>>,
463                IntoIter: IntoIterator<IntoIter = Iter, Item = Value<&'a NewDType>>,
464                Self: $add_cloned_valiter_trait<NewLabel, NewDType>,
465                NewDType: 'a,
466            {
467                $add_cloned_valiter_trait::$add_cloned_valiter_fn(self, iter)
468            }
469            $(#[$add_cloned_iter_fn_doc])*
470            pub fn $add_cloned_iter_fn<'a, NewLabel, NewDType, IntoIter, Iter>(
471                self,
472                iter: IntoIter,
473            ) -> DataStore<<Self as $add_cloned_iter_trait<NewLabel, NewDType>>::OutputFields>
474            where
475                Iter: Iterator<Item = &'a NewDType>,
476                IntoIter: IntoIterator<IntoIter = Iter, Item = &'a NewDType>,
477                Self: $add_cloned_iter_trait<NewLabel, NewDType>,
478                NewDType: 'a,
479            {
480                $add_cloned_iter_trait::$add_cloned_iter_fn(self, iter)
481            }
482
483            $(#[$add_empty_fn_doc])*
484            pub fn $add_empty_fn<NewLabel, NewDType>(
485                self,
486            ) -> DataStore<<Self as $add_empty_trait<NewLabel, NewDType>>::OutputFields>
487            where
488                Self: $add_empty_trait<NewLabel, NewDType>,
489            {
490                $add_empty_trait::$add_empty_fn(self)
491            }
492        }
493    };
494}
495
496make_add_field![
497    /// Trait for pushing a [FieldData](../field/struct.FieldData.html) onto the front of a
498    /// [DataStore](struct.DataStore.html)'s fields cons-list.
499    trait PushFrontField;
500    /// Push a [FieldData](../field/struct.FieldData.html) onto the front of this store's
501    /// fields cons-list.
502    fn push_front_field;
503
504    /// Trait for pushing a field onto the front of a [DataStore](struct.DataStore.html)'s fields
505    /// cons-list using data from an iterator of [Value](../field/enum.Value.html) objects.
506    trait PushFrontFromValueIter;
507    /// Push a field onto the front of this store's fields cons-list using data from an iterator
508    /// of [Value](../field/enum.Value.html) objects.
509    fn push_front_from_value_iter;
510
511    /// Trait for pushing a field onto the front of a [DataStore](struct.DataStore.html)'s fields
512    /// cons-list using data from an iterator of objects. Field is assumed to have no missing data.
513    trait PushFrontFromIter;
514    /// Push a field onto the front of this store's fields cons-list using data from an iterator
515    /// of objects.
516    fn push_front_from_iter;
517
518    /// Trait for pushing a field onto the front of a [DataStore](struct.DataStore.html)'s fields
519    /// cons-list cloning data from an iterator of [Value](../field/enum.Value.html) objects.
520    trait PushFrontClonedFromValueIter;
521    /// Push a field onto the front of this store's fields cons-list cloning data from an iterator
522    /// of [Value](../field/enum.Value.html) objects.
523    fn push_front_cloned_from_value_iter;
524
525    /// Trait for pushing a field onto the front of a [DataStore](struct.DataStore.html)'s fields
526    /// cons-list cloning data from an iterator of objects. Field is assumed to have no missing
527    /// data.
528    trait PushFrontClonedFromIter;
529    /// Push a field onto the front of this store's fields cons-list cloning data from an iterator
530    /// of objects.
531    fn push_front_cloned_from_iter;
532
533    /// Trait for pushing an empty field onto the front of a [DataStore](struct.DataStore.html)'s
534    /// fields cons-list.
535    trait PushFrontEmpty;
536    /// Push an empty field into the front of this store's fields cons-list.
537    fn push_front_empty;
538
539    PushFront push_front PushedFrontField
540];
541
542make_add_field![
543    /// Trait for pushing a [FieldData](../field/struct.FieldData.html) onto the back of a
544    /// [DataStore](struct.DataStore.html)'s fields cons-list.
545    trait PushBackField;
546    /// Push a [FieldData](../field/struct.FieldData.html) onto the back of this store's
547    /// fields cons-list.
548    fn push_back_field;
549
550    /// Trait for pushing a field onto the back of a [DataStore](struct.DataStore.html)'s fields
551    /// cons-list using data from an iterator of [Value](../field/enum.Value.html) objects.
552    trait PushBackFromValueIter;
553    /// Push a field onto the back of this store's fields cons-list using data from an iterator
554    /// of [Value](../field/enum.Value.html) objects.
555    fn push_back_from_value_iter;
556
557    /// Trait for pushing a field onto the back of a [DataStore](struct.DataStore.html)'s fields
558    /// cons-list using data from an iterator of objects. Field is assumed to have no missing data.
559    trait PushBackFromIter;
560    /// Push a field onto the back of this store's fields cons-list using data from an iterator
561    /// of objects.
562    fn push_back_from_iter;
563
564    /// Trait for pushing a field onto the back of a [DataStore](struct.DataStore.html)'s fields
565    /// cons-list cloning data from an iterator of [Value](../field/enum.Value.html) objects.
566    trait PushBackClonedFromValueIter;
567    /// Push a field onto the back of this store's fields cons-list cloning data from an iterator
568    /// of [Value](../field/enum.Value.html) objects.
569    fn push_back_cloned_from_value_iter;
570
571    /// Trait for pushing a field onto the back of a [DataStore](struct.DataStore.html)'s fields
572    /// cons-list cloning data from an iterator of objects. Field is assumed to have no missing
573    /// data.
574    trait PushBackClonedFromIter;
575    /// Push a field onto the back of this store's fields cons-list cloning data from an iterator
576    /// of objects.
577    fn push_back_cloned_from_iter;
578
579    /// Trait for pushing an empty field onto the back of a [DataStore](struct.DataStore.html)'s
580    /// fields cons-list.
581    trait PushBackEmpty;
582    /// Push an empty field into the back of this store's fields cons-list.
583    fn push_back_empty;
584
585    PushBack push_back PushedBackField
586];
587
588impl<Label, Fields> SelectFieldByLabel<Label> for DataStore<Fields>
589where
590    Fields: AssocStorage,
591    Fields::Storage: LookupElemByLabel<Label>,
592    ElemOf<Fields::Storage, Label>: Typed,
593    ElemOf<Fields::Storage, Label>: Valued<Value = DataRef<TypeOfElemOf<Fields::Storage, Label>>>,
594    TypeOfElemOf<Fields::Storage, Label>: Debug,
595{
596    type DType = TypeOfElemOf<Fields::Storage, Label>;
597    type Output = DataRef<Self::DType>;
598
599    fn select_field(&self) -> Self::Output {
600        DataRef::clone(LookupElemByLabel::<Label>::elem(&self.data).value_ref())
601    }
602}
603impl<Fields> FieldSelect for DataStore<Fields> where Fields: AssocStorage {}
604
605/// Trait to determine the [FrameLookupCons](../view/type.FrameLookupCons.html) for a field list.
606pub trait AssocFrameLookup {
607    /// The associated `FrameLookupCons`.
608    type Output;
609}
610impl AssocFrameLookup for Nil {
611    type Output = Nil;
612}
613impl<Label, Value, Tail> AssocFrameLookup for LVCons<Label, Value, Tail>
614where
615    Tail: AssocFrameLookup,
616{
617    type Output = FrameLookupCons<Label, UTerm, Label, <Tail as AssocFrameLookup>::Output>;
618}
619
620impl<Fields> DataStore<Fields>
621where
622    Fields: AssocStorage + AssocFrameLookup,
623{
624    /// Wrap this `DataStore` with a [DataView](../view/struct.DataView.html) object. Utility
625    /// function that leverages [IntoView](trait.IntoView.html).
626    pub fn into_view(self) -> <Self as IntoView>::Output
627    where
628        Self: IntoView,
629    {
630        IntoView::into_view(self)
631    }
632}
633
634/// Trait that provides a method to convert `Self` into a [DataView](../view/struct.DataView.html)
635/// object.
636pub trait IntoView {
637    /// The `Labels` type parameter for the output `DataView`.
638    type Labels;
639    /// The `Frames` type parameter for the output `DataView`.
640    type Frames;
641    /// The output `DataView` (should always be `DataView<Self::Labels, Self::Frames>`).
642    type Output; // = DataView<Self::Labels, Self::Frames>
643    /// Convert `self` into a [DataView](../view/struct.DataView.html) object.
644    fn into_view(self) -> Self::Output;
645}
646impl<Fields> IntoView for DataStore<Fields>
647where
648    Fields: AssocStorage + AssocFrameLookup + SimpleFrameFields,
649{
650    type Labels = <Fields as AssocFrameLookup>::Output;
651    type Frames = ViewFrameCons<UTerm, DataFrame<<Fields as SimpleFrameFields>::Fields, Self>, Nil>;
652    type Output = DataView<Self::Labels, Self::Frames>;
653
654    fn into_view(self) -> Self::Output {
655        DataView::new(ViewFrameCons {
656            head: DataFrame::from(self).into(),
657            tail: Nil,
658        })
659    }
660}
661
662/// Type alias for a [DataStore](struct.DataStore.html) constructed with a single field.
663pub type SingleFieldStore<Label, T> =
664    DataStore<<DataStore<Nil> as PushFrontFromValueIter<Label, T>>::OutputFields>;
665
666impl<Label, I, T> IntoView for Labeled<Label, I>
667where
668    I: Iterator<Item = Value<T>>,
669    DataStore<Nil>: PushFrontFromValueIter<Label, T>,
670    <DataStore<Nil> as PushFrontFromValueIter<Label, T>>::OutputFields:
671        AssocFrameLookup + SimpleFrameFields,
672{
673    type Labels = <SingleFieldStore<Label, T> as IntoView>::Labels;
674    type Frames = <SingleFieldStore<Label, T> as IntoView>::Frames;
675    type Output = <SingleFieldStore<Label, T> as IntoView>::Output;
676
677    fn into_view(self) -> Self::Output {
678        DataStore::<Nil>::empty()
679            .push_front_from_value_iter(self.value)
680            .into_view()
681    }
682}
683
684/// Trait for converting field data into a [DataStore](struct.DataStore.html) object with label
685/// `Label`.
686pub trait IntoStore<Label> {
687    /// The reulting `DataStore` object.
688    type Output;
689
690    /// Wraps this field data in a `DataStore` and returns it.
691    fn into_store(self) -> Self::Output;
692}
693
694impl<Label, T> IntoStore<Label> for FieldData<T>
695where
696    Label: Debug,
697    T: Default + Debug,
698{
699    type Output = SingleFieldStore<Label, T>;
700
701    fn into_store(self) -> Self::Output {
702        DataStore::<Nil>::empty().push_front_field(self)
703    }
704}
705
706#[cfg(test)]
707mod tests {
708
709    use std::fmt::Debug;
710    use std::path::Path;
711    use typenum::U0;
712
713    use csv_sniffer::metadata::Metadata;
714
715    use super::{DataStore, NRows};
716    use cons::*;
717    use field::Value;
718    use select::FieldSelect;
719    use source::csv::{CsvReader, CsvSource, IntoCsvSrcSchema};
720
721    fn load_csv_file<Schema>(
722        filename: &str,
723        spec: Schema,
724    ) -> (CsvReader<Schema::CsvSrcSchema>, Metadata)
725    where
726        Schema: IntoCsvSrcSchema,
727        <Schema as IntoCsvSrcSchema>::CsvSrcSchema: Debug,
728    {
729        let data_filepath = Path::new(file!()) // start as this file
730            .parent()
731            .unwrap() // navigate up to src directory
732            .parent()
733            .unwrap() // navigate up to root directory
734            .join("tests") // navigate into integration tests directory
735            .join("data") // navigate into data directory
736            .join(filename); // navigate to target file
737
738        let source = CsvSource::new(data_filepath).unwrap();
739        (
740            CsvReader::new(&source, spec).unwrap(),
741            source.metadata().clone(),
742        )
743    }
744
745    tablespace![
746        pub table gdp {
747            CountryName: String,
748            CountryCode: String,
749            Year1983: f64,
750        }
751    ];
752
753    #[test]
754    fn storage_create() {
755        let ds = DataStore::<Nil>::empty();
756
757        type TestTablespace = U0;
758        first_label![Test, TestTablespace, u64];
759
760        let data = vec![
761            Value::Exists(4u64),
762            Value::Exists(1),
763            Value::Na,
764            Value::Exists(3),
765            Value::Exists(7),
766            Value::Exists(8),
767            Value::Na,
768        ];
769        let expected_nrows = data.len();
770
771        let ds = ds.push_back_from_iter::<Test, _, _, _>(data);
772        println!("{:?}", ds);
773        assert_eq!(ds.nrows(), expected_nrows);
774        assert_eq!(ds.field::<Test>().len(), expected_nrows);
775
776        let gdp_schema = schema![
777            fieldname gdp::CountryName = "Country Name";
778            fieldname gdp::CountryCode = "Country Code";
779            fieldname gdp::Year1983 = "1983";
780        ];
781
782        let (mut csv_rdr, _metadata) = load_csv_file("gdp.csv", gdp_schema.clone());
783        let ds = csv_rdr.read().unwrap();
784        const EXPECTED_GDP_NROWS: usize = 264;
785        assert_eq!(ds.nrows(), EXPECTED_GDP_NROWS);
786        assert_eq!(ds.field::<gdp::CountryName>().len(), EXPECTED_GDP_NROWS);
787    }
788}