1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! TODO(doc): @quake
use crate::ChainStore;
use ckb_traits::{CellDataProvider, EpochProvider, HeaderProvider};
use ckb_types::{
    bytes::Bytes,
    core::{BlockExt, BlockNumber, EpochExt, HeaderView},
    packed::{Byte32, OutPoint},
};
use std::sync::Arc;

/// DataLoaderWrapper wrap`ChainStore`
/// impl `HeaderProvider` `CellDataProvider` `EpochProvider`
pub struct DataLoaderWrapper<T>(Arc<T>);

// auto derive don't work
impl<T> Clone for DataLoaderWrapper<T> {
    fn clone(&self) -> Self {
        DataLoaderWrapper(Arc::clone(&self.0))
    }
}

/// Auto transform Arc wrapped `ChainStore` to `DataLoaderWrapper`
pub trait AsDataLoader<T> {
    /// Return arc cloned DataLoaderWrapper
    fn as_data_loader(&self) -> DataLoaderWrapper<T>;
}

impl<T> AsDataLoader<T> for Arc<T>
where
    T: ChainStore,
{
    fn as_data_loader(&self) -> DataLoaderWrapper<T> {
        DataLoaderWrapper(Arc::clone(self))
    }
}

impl<T> CellDataProvider for DataLoaderWrapper<T>
where
    T: ChainStore,
{
    fn get_cell_data(&self, out_point: &OutPoint) -> Option<Bytes> {
        ChainStore::get_cell_data(self.0.as_ref(), out_point).map(|(data, _)| data)
    }

    fn get_cell_data_hash(&self, out_point: &OutPoint) -> Option<Byte32> {
        ChainStore::get_cell_data_hash(self.0.as_ref(), out_point)
    }
}

impl<T> HeaderProvider for DataLoaderWrapper<T>
where
    T: ChainStore,
{
    fn get_header(&self, block_hash: &Byte32) -> Option<HeaderView> {
        ChainStore::get_block_header(self.0.as_ref(), block_hash)
    }
}

impl<T> EpochProvider for DataLoaderWrapper<T>
where
    T: ChainStore,
{
    fn get_epoch_ext(&self, header: &HeaderView) -> Option<EpochExt> {
        ChainStore::get_block_epoch_index(self.0.as_ref(), &header.hash())
            .and_then(|index| ChainStore::get_epoch_ext(self.0.as_ref(), &index))
    }

    fn get_block_hash(&self, number: BlockNumber) -> Option<Byte32> {
        ChainStore::get_block_hash(self.0.as_ref(), number)
    }

    fn get_block_ext(&self, block_hash: &Byte32) -> Option<BlockExt> {
        ChainStore::get_block_ext(self.0.as_ref(), block_hash)
    }

    fn get_block_header(&self, hash: &Byte32) -> Option<HeaderView> {
        ChainStore::get_block_header(self.0.as_ref(), hash)
    }
}

/// Borrowed DataLoaderWrapper with lifetime
pub struct BorrowedDataLoaderWrapper<'a, T>(&'a T);
impl<'a, T: ChainStore> BorrowedDataLoaderWrapper<'a, T> {
    /// Construct new BorrowedDataLoaderWrapper
    pub fn new(source: &'a T) -> Self {
        BorrowedDataLoaderWrapper(source)
    }
}

impl<'a, T: ChainStore> CellDataProvider for BorrowedDataLoaderWrapper<'a, T> {
    fn get_cell_data(&self, out_point: &OutPoint) -> Option<Bytes> {
        self.0.get_cell_data(out_point).map(|(data, _)| data)
    }

    fn get_cell_data_hash(&self, out_point: &OutPoint) -> Option<Byte32> {
        self.0.get_cell_data_hash(out_point)
    }
}

impl<'a, T: ChainStore> HeaderProvider for BorrowedDataLoaderWrapper<'a, T> {
    fn get_header(&self, block_hash: &Byte32) -> Option<HeaderView> {
        self.0.get_block_header(block_hash)
    }
}

impl<'a, T: ChainStore> EpochProvider for BorrowedDataLoaderWrapper<'a, T> {
    fn get_epoch_ext(&self, header: &HeaderView) -> Option<EpochExt> {
        ChainStore::get_block_epoch_index(self.0, &header.hash())
            .and_then(|index| ChainStore::get_epoch_ext(self.0, &index))
    }

    fn get_block_hash(&self, number: BlockNumber) -> Option<Byte32> {
        ChainStore::get_block_hash(self.0, number)
    }

    fn get_block_ext(&self, block_hash: &Byte32) -> Option<BlockExt> {
        ChainStore::get_block_ext(self.0, block_hash)
    }

    fn get_block_header(&self, hash: &Byte32) -> Option<HeaderView> {
        ChainStore::get_block_header(self.0, hash)
    }
}