check this code:

fn main() {
    init_with_level(Level::Info).unwrap();

    let args: Args = Args::parse();

    args.check().unwrap_or_else(|e| {
        error!("{}", e);
        std::process::exit(1);
    });

    info!("{:?}", args);

    rayon::ThreadPoolBuilder::new()
        .num_threads(args.threads)
        .build_global()
        .unwrap();

    let start = std::time::Instant::now();

    let bed = reader(&args.bed).unwrap();
    let isoseq = reader(&args.reads).unwrap();

    info!("Parsing records...");

    let (tracks, pseudomap) = parse_tracks(&bed).unwrap();
    let (reads, _) = parse_tracks(&isoseq).unwrap();

    info!(
        "Parsed {} annotation tracks and {} reads and started pseudomapping...",
        tracks.len(),
        reads.len()
    );

    let index = Arc::new(Track::new(tracks, pseudomap, reads));
    let bucket = Arc::new(DashMap::<&String, Bucket>::new());
    let pocket = Arc::new(DashMap::<Pocket, Vec<String>>::new());

    index.reads.par_iter().for_each(|(read, record)| {
        index
            .pseudomap
            .get(&record.chrom)
            .unwrap()
            .par_iter()
            .for_each(|(start, end, id)| {
                if record.tx_start >= *start - BOUNDARY && record.tx_end <= *end + BOUNDARY {
                    // a bucket needs to be of the form:
                    //      read:
                    //          [(start, end)] -> read_exons
                    //          [(start, end)] -> gene_exons
                    // since a read could be pseudomapped to multiple transcripts,
                    // the gene_exons vector will be extended with the exons of each
                    // transcript.
                    let mut b_acc = bucket.entry(read).or_insert(Bucket::default());

                    b_acc.id.push(id.clone());
                    b_acc
                        .gene_exons
                        .extend(index.tracks.get(id).unwrap().coords.clone());

                    if b_acc.read_exons.is_empty() {
                        b_acc.read_exons = record.coords.clone();
                    }
                }
                // } else {
                //     bucket.entry(read).or_insert(Bucket::default());
                // }
            });
    });

    if bucket.len() == 0 {
        error!("No reads were pseudomapped to the provided annotation.");
        std::process::exit(1);
    } else if bucket.len() < index.reads.len() / 2 {
        info!(
            "Pseudomapped {} ({:.2}%) to the provided annotation.",
            bucket.len(),
            (bucket.len() as f64 / index.reads.len() as f64) * 100.0
        );
        warn!("Less than 50% of reads were pseudomapped to the provided annotation.");
    } else {
        info!(
            "Pseudomapped {} ({:.2}%) reads to the provided annotation.",
            bucket.len(),
            (bucket.len() as f64 / index.reads.len() as f64) * 100.0
        );
    }

    info!("Classifying reads into pockets...");

    bucket.par_iter_mut().for_each(|mut entry| {
        entry.value_mut().gene_exons.par_sort_unstable();
        entry.value_mut().gene_exons.dedup();

        let read = entry.key();
        let exons = entry.value();

        if exons.read_exons.is_empty() {
            pocket
                .entry(Pocket::Unmapped)
                .or_insert(Vec::new())
                .push(index.reads[*read].line.clone());
            return;
        }

        let state = find_exon_matches(&exons);

        // fill pockets based on read state
        let id = if state { Pocket::Pass } else { Pocket::Fail };
        let mut p_acc = pocket.entry(id).or_insert(Vec::new());
        p_acc.push(index.reads[*read].line.clone());
    });

    // do we need a sorting step?
    // pocket.par_iter_mut().for_each(|mut entry| {
    //     entry.value_mut().par_sort_unstable();
    // });

    pocket.iter().for_each(|entry| {
        info!(
            "Pocket: {:?} contains {} reads.",
            entry.key(),
            entry.value().len()
        );
    });

    write_objs(&pocket);

    let elapsed = start.elapsed();
    info!("Elapsed: {:?}", elapsed);
}

fn find_exon_matches(bucket: &Bucket) -> bool {
    let mut gene_exon_indices = VecDeque::from_iter(0..bucket.gene_exons.len());
    // let mut matches = Vec::new();
    let mut status = true;

    for (i, &(start, end)) in bucket.read_exons.iter().enumerate() {
        let is_first_or_last = i == 0 || i == bucket.read_exons.len() - 1;

        while let Some(&gene_exon_index) = gene_exon_indices.front() {
            let (gene_start, gene_end) = bucket.gene_exons[gene_exon_index];

            let mut is_match = false;
            // let mut is_retention = false;

            if is_first_or_last {
                if i == 0 {
                    // first exon start is allowed to be less than gene start
                    is_match = end <= gene_end;
                } else {
                    // last exon end is allowed to be greater than gene end
                    is_match = start >= gene_start;
                }
            } else {
                // for any middle exons, they must be fully contained within a gene exon
                is_match = start >= gene_start && end <= gene_end;
                // is_retention = start < gene_start && end > gene_end
                //     || start < gene_start && end <= gene_end
                //     || start >= gene_start && end > gene_end;
            }

            if is_match {
                // matches.push(gene_exon_index);
                status = true;
                gene_exon_indices.pop_front();
                break;
            } else if gene_end < start {
                // if the current gene exon ends before the read exon starts,
                // it can’t be a match, and we can safely discard it.
                status = true;
                gene_exon_indices.pop_front();
            } else {
                // if there is evidence of intron retention, break the loop
                // and put this read in a separate bucket
                // println!("Intron retention detected for read: {}", read);
                status = false;
                break;
            }
        } // end while
        if status == false {
            break;
        }
    } // end for

    status
}

if there are improvements on how to make it a lot more faster or more efficient, please implement them. Use any crate, trick, algorithm you want. You are free to modiify anything-