leyline-http 0.1.1

HTTP client that mimics browsers on the wire
Documentation
use super::scan::Tag;

const VOID: [&str; 13] = [
    "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "source", "track",
    "wbr",
];

#[derive(Clone, Copy, PartialEq, Eq)]
enum Legend {
    Before,
    Inside,
    After,
}

struct Level {
    disabled: bool,
    legend: Legend,
    depth: usize,
}

#[derive(Default)]
pub(super) struct Fieldsets {
    stack: Vec<Level>,
}

impl Fieldsets {
    pub(super) fn tag(&mut self, tag: &Tag<'_>) {
        match (tag.closing, tag.name.as_str()) {
            (false, "fieldset") => self.stack.push(Level {
                disabled: tag.has("disabled"),
                legend: Legend::Before,
                depth: 0,
            }),
            (true, "fieldset") => {
                self.stack.pop();
            }
            (false, name) => self.open(name),
            (true, name) => self.close(name),
        }
    }

    fn open(&mut self, name: &str) {
        let Some(level) = self.stack.last_mut() else {
            return;
        };
        if name == "legend" && level.depth == 0 && level.legend == Legend::Before {
            level.legend = Legend::Inside;
        }
        if !VOID.contains(&name) {
            level.depth += 1;
        }
    }

    fn close(&mut self, name: &str) {
        let Some(level) = self.stack.last_mut() else {
            return;
        };
        level.depth = level.depth.saturating_sub(1);
        if name == "legend" && level.depth == 0 && level.legend == Legend::Inside {
            level.legend = Legend::After;
        }
    }

    pub(super) fn disabled(&self) -> bool {
        self.stack
            .iter()
            .any(|level| level.disabled && level.legend != Legend::Inside)
    }
}