notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

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 }