jobs.rs (3853B)
1 use egui::TextureHandle; 2 use hashbrown::{hash_map::RawEntryMut, HashMap}; 3 use notedeck::JobPool; 4 use poll_promise::Promise; 5 6 #[derive(Default)] 7 pub struct JobsCache { 8 jobs: HashMap<JobIdOwned, JobState>, 9 } 10 11 pub enum JobState { 12 Pending(Promise<Option<Result<Job, JobError>>>), 13 Error(JobError), 14 Completed(Job), 15 } 16 17 pub enum JobError { 18 InvalidParameters, 19 } 20 21 #[derive(Debug)] 22 pub enum JobParams<'a> { 23 Blurhash(BlurhashParams<'a>), 24 } 25 26 #[derive(Debug)] 27 pub enum JobParamsOwned { 28 Blurhash(BlurhashParamsOwned), 29 } 30 31 impl<'a> From<BlurhashParams<'a>> for BlurhashParamsOwned { 32 fn from(params: BlurhashParams<'a>) -> Self { 33 BlurhashParamsOwned { 34 blurhash: params.blurhash.to_owned(), 35 url: params.url.to_owned(), 36 ctx: params.ctx.clone(), 37 } 38 } 39 } 40 41 impl<'a> From<JobParams<'a>> for JobParamsOwned { 42 fn from(params: JobParams<'a>) -> Self { 43 match params { 44 JobParams::Blurhash(bp) => JobParamsOwned::Blurhash(bp.into()), 45 } 46 } 47 } 48 49 #[derive(Debug)] 50 pub struct BlurhashParams<'a> { 51 pub blurhash: &'a str, 52 pub url: &'a str, 53 pub ctx: &'a egui::Context, 54 } 55 56 #[derive(Debug)] 57 pub struct BlurhashParamsOwned { 58 pub blurhash: String, 59 pub url: String, 60 pub ctx: egui::Context, 61 } 62 63 impl JobsCache { 64 pub fn get_or_insert_with< 65 'a, 66 F: FnOnce(Option<JobParamsOwned>) -> Result<Job, JobError> + Send + 'static, 67 >( 68 &'a mut self, 69 job_pool: &mut JobPool, 70 jobid: &JobId, 71 params: Option<JobParams>, 72 run_job: F, 73 ) -> &'a mut JobState { 74 match self.jobs.raw_entry_mut().from_key(jobid) { 75 RawEntryMut::Occupied(entry) => 's: { 76 let mut state = entry.into_mut(); 77 78 let JobState::Pending(promise) = &mut state else { 79 break 's state; 80 }; 81 82 let Some(res) = promise.ready_mut() else { 83 break 's state; 84 }; 85 86 let Some(res) = res.take() else { 87 tracing::error!("Failed to take the promise for job: {:?}", jobid); 88 break 's state; 89 }; 90 91 *state = match res { 92 Ok(j) => JobState::Completed(j), 93 Err(e) => JobState::Error(e), 94 }; 95 96 state 97 } 98 RawEntryMut::Vacant(entry) => { 99 let owned_params = params.map(JobParams::into); 100 let wrapped: Box<dyn FnOnce() -> Option<Result<Job, JobError>> + Send + 'static> = 101 Box::new(move || Some(run_job(owned_params))); 102 103 let promise = Promise::spawn_async(job_pool.schedule(wrapped)); 104 105 let (_, state) = entry.insert(jobid.into(), JobState::Pending(promise)); 106 107 state 108 } 109 } 110 } 111 112 pub fn get(&self, jobid: &JobId) -> Option<&JobState> { 113 self.jobs.get(jobid) 114 } 115 } 116 117 impl<'a> From<&JobId<'a>> for JobIdOwned { 118 fn from(jobid: &JobId<'a>) -> Self { 119 match jobid { 120 JobId::Blurhash(s) => JobIdOwned::Blurhash(s.to_string()), 121 } 122 } 123 } 124 125 impl hashbrown::Equivalent<JobIdOwned> for JobId<'_> { 126 fn equivalent(&self, key: &JobIdOwned) -> bool { 127 match (self, key) { 128 (JobId::Blurhash(a), JobIdOwned::Blurhash(b)) => *a == b.as_str(), 129 } 130 } 131 } 132 133 #[derive(Debug, PartialEq, Eq, Clone, Hash)] 134 enum JobIdOwned { 135 Blurhash(String), // image URL 136 } 137 138 #[derive(Debug, Hash)] 139 pub enum JobId<'a> { 140 Blurhash(&'a str), // image URL 141 } 142 143 pub enum Job { 144 Blurhash(Option<TextureHandle>), 145 } 146 147 impl std::fmt::Debug for Job { 148 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 149 match self { 150 Job::Blurhash(_) => write!(f, "Blurhash"), 151 } 152 } 153 }