oxygengine_core/fetch/
mod.rs1pub mod engines;
2
3use crate::{id::ID, Scalar};
4use std::{
5 mem::replace,
6 sync::{Arc, RwLock},
7};
8
9pub type FetchProcessId = ID<FetchProcess>;
10
11#[derive(Debug, PartialEq, Copy, Clone)]
12pub enum FetchCancelReason {
13 User,
14 Error,
15}
16
17#[derive(Debug, PartialEq, Copy, Clone)]
18pub enum FetchStatus {
19 Empty,
20 InProgress(Scalar),
21 Done,
22 Canceled(FetchCancelReason),
23 Read,
24}
25
26impl Default for FetchStatus {
27 fn default() -> Self {
28 Self::Empty
29 }
30}
31
32#[derive(Clone)]
33pub struct FetchProcess {
34 id: FetchProcessId,
35 inner: Arc<RwLock<(FetchStatus, Option<Vec<u8>>)>>,
36}
37
38impl Default for FetchProcess {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44impl FetchProcess {
45 #[inline]
46 pub fn new() -> Self {
47 Self {
48 id: FetchProcessId::new(),
49 inner: Arc::new(RwLock::new((FetchStatus::Empty, None))),
50 }
51 }
52
53 #[inline]
54 pub fn new_start() -> Self {
55 Self {
56 id: FetchProcessId::new(),
57 inner: Arc::new(RwLock::new((FetchStatus::InProgress(0.0), None))),
58 }
59 }
60
61 #[inline]
62 pub fn new_done(data: Vec<u8>) -> Self {
63 Self {
64 id: FetchProcessId::new(),
65 inner: Arc::new(RwLock::new((FetchStatus::Done, Some(data)))),
66 }
67 }
68
69 #[inline]
70 pub fn new_cancel(reason: FetchCancelReason) -> Self {
71 Self {
72 id: FetchProcessId::new(),
73 inner: Arc::new(RwLock::new((FetchStatus::Canceled(reason), None))),
74 }
75 }
76
77 #[inline]
78 pub fn id(&self) -> FetchProcessId {
79 self.id
80 }
81
82 pub fn status(&self) -> FetchStatus {
83 self.inner.read().map(|meta| meta.0).unwrap_or_default()
84 }
85
86 pub fn start(&mut self) {
87 if let Ok(mut meta) = self.inner.write() {
88 *meta = (FetchStatus::InProgress(0.0), None);
89 }
90 }
91
92 pub fn progress(&mut self, value: Scalar) {
93 if let Ok(mut meta) = self.inner.write() {
94 *meta = (FetchStatus::InProgress(value), None);
95 }
96 }
97
98 pub fn done(&mut self, data: Vec<u8>) {
99 if let Ok(mut meta) = self.inner.write() {
100 *meta = (FetchStatus::Done, Some(data));
101 }
102 }
103
104 pub fn cancel(&mut self, reason: FetchCancelReason) {
105 if let Ok(mut meta) = self.inner.write() {
106 *meta = (FetchStatus::Canceled(reason), None);
107 }
108 }
109
110 pub fn readers_count(&self) -> usize {
111 Arc::strong_count(&self.inner) + Arc::weak_count(&self.inner) - 1
112 }
113
114 pub fn read(&self) -> Option<Vec<u8>> {
115 if let Ok(mut meta) = self.inner.write() {
116 if meta.0 == FetchStatus::Done {
117 let old: (FetchStatus, Option<Vec<u8>>) =
118 replace(&mut meta, (FetchStatus::Read, None));
119 return old.1;
120 }
121 }
122 None
123 }
124
125 pub fn byte_size(&self) -> Option<usize> {
126 if let Ok(meta) = self.inner.read() {
127 if meta.0 == FetchStatus::Done {
128 if let Some(bytes) = meta.1.as_ref() {
129 return Some(bytes.len());
130 }
131 }
132 }
133 None
134 }
135}
136
137pub trait FetchEngine: Send + Sync {
138 fn fetch(&mut self, path: &str) -> Result<Box<FetchProcess>, FetchStatus>;
139
140 fn cancel(&mut self, mut reader: FetchProcess) {
141 reader.cancel(FetchCancelReason::User)
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 #[allow(unused_imports)]
148 use super::*;
149
150 #[test]
151 #[cfg(not(feature = "web"))]
152 fn test_fetch() {
153 let mut engine = engines::fs::FsFetchEngine::new(&".");
154 let reader = engine.fetch("Cargo.toml").unwrap();
155 let reader2 = reader.clone();
156 #[cfg(feature = "parallel")]
157 {
158 assert_eq!(reader.status(), FetchStatus::InProgress(0.0));
159 assert_eq!(reader2.status(), FetchStatus::InProgress(0.0));
160 }
161 loop {
162 match reader.status() {
163 FetchStatus::InProgress(_) => continue,
164 _ => break,
165 }
166 }
167 assert_eq!(reader.status(), FetchStatus::Done);
168 assert_eq!(reader2.status(), FetchStatus::Done);
169 assert!(!reader.read().unwrap().is_empty());
170 assert_eq!(reader.status(), FetchStatus::Read);
171 assert_eq!(reader2.status(), FetchStatus::Read);
172 }
173}