use rustc_hash::FxHashMap as HashMap;
use shuck_ast::{CaseCommand, CaseItem, Span};
use crate::command::stmt_span;
use crate::comments::{BranchPrefixComment, SourceComment};
use super::FactSpan;
#[derive(Debug, Clone, Default)]
pub(super) struct CaseFacts<'source> {
case_facts: HashMap<FactSpan, CaseCommandFacts>,
case_item_facts: HashMap<FactSpan, CaseItemFacts<'source>>,
}
impl<'source> CaseFacts<'source> {
pub(super) fn case_command(&self, command: &CaseCommand) -> Option<&CaseCommandFacts> {
self.case_facts.get(&FactSpan::from(command.span))
}
pub(super) fn case_item(&self, item: &CaseItem) -> Option<&CaseItemFacts<'source>> {
self.case_item_facts.get(&case_item_key(item))
}
pub(super) fn insert_case_command(&mut self, command: &CaseCommand, facts: CaseCommandFacts) {
self.case_facts.insert(FactSpan::from(command.span), facts);
}
pub(super) fn insert_case_item(&mut self, item: &CaseItem, facts: CaseItemFacts<'source>) {
self.case_item_facts.insert(case_item_key(item), facts);
}
#[cfg(feature = "benchmarking")]
pub(super) fn len(&self) -> usize {
self.case_facts.len() + self.case_item_facts.len()
}
}
#[derive(Debug, Clone)]
pub(crate) struct CaseCommandFacts {
pub(super) esac_span: Option<Span>,
pub(super) body_fallback_upper_bound: usize,
pub(super) has_blank_line_after_in: bool,
pub(super) has_blank_line_before_esac: bool,
pub(super) suffix_comments_before_esac: Vec<BranchPrefixComment>,
}
impl CaseCommandFacts {
pub(crate) fn esac_span(&self) -> Option<Span> {
self.esac_span
}
pub(crate) fn body_fallback_upper_bound(&self) -> usize {
self.body_fallback_upper_bound
}
pub(crate) fn has_blank_line_after_in(&self) -> bool {
self.has_blank_line_after_in
}
pub(crate) fn has_blank_line_before_esac(&self) -> bool {
self.has_blank_line_before_esac
}
pub(crate) fn suffix_comments_before_esac(&self) -> &[BranchPrefixComment] {
&self.suffix_comments_before_esac
}
}
#[derive(Debug, Clone)]
pub(crate) struct CaseItemFacts<'source> {
pub(super) suffix_comment_start_line: Option<usize>,
pub(super) has_blank_line_before: bool,
pub(super) has_blank_line_after_pattern: bool,
pub(super) has_blank_line_before_terminator: bool,
pub(super) prefix_comments: Vec<SourceComment<'source>>,
pub(super) pattern_suffix_comment: Option<SourceComment<'source>>,
pub(super) terminator_suffix_comment: Option<SourceComment<'source>>,
}
impl<'source> CaseItemFacts<'source> {
pub(crate) fn suffix_comment_start_line(&self) -> Option<usize> {
self.suffix_comment_start_line
}
pub(crate) fn has_blank_line_before(&self) -> bool {
self.has_blank_line_before
}
pub(crate) fn has_blank_line_after_pattern(&self) -> bool {
self.has_blank_line_after_pattern
}
pub(crate) fn has_blank_line_before_terminator(&self) -> bool {
self.has_blank_line_before_terminator
}
pub(crate) fn prefix_comments(&self) -> &[SourceComment<'source>] {
&self.prefix_comments
}
pub(crate) fn pattern_suffix_comment(&self) -> Option<SourceComment<'source>> {
self.pattern_suffix_comment
}
pub(crate) fn terminator_suffix_comment(&self) -> Option<SourceComment<'source>> {
self.terminator_suffix_comment
}
}
fn case_item_key(item: &CaseItem) -> FactSpan {
let start = item
.patterns
.first()
.map(|pattern| pattern.span.start.offset)
.unwrap_or(item.body.span.start.offset);
let end = item
.terminator_span
.map(|span| span.end.offset)
.or_else(|| item.body.last().map(|stmt| stmt_span(stmt).end.offset))
.or_else(|| item.patterns.last().map(|pattern| pattern.span.end.offset))
.unwrap_or(item.body.span.end.offset);
FactSpan::from_offsets(start, end)
}