use super::{
BrowserName,
compression::{LazyBlob, read_varint},
};
use crate::data::decode_browser_name;
pub use crate::generated::caniuse_feature_matching::get_feature_stat;
static FEATURES: LazyBlob =
LazyBlob::new(include_bytes!("../../generated/caniuse_feature_matching.bin.deflate"));
pub struct FeatureSet {
yes: Vec< &'static str>,
partial: Vec< &'static str>,
}
impl FeatureSet {
pub fn new(yes: Vec<&'static str>, partial: Vec<&'static str>) -> Self {
Self { yes, partial }
}
pub fn supports(&self, version: &str, include_partial: bool) -> bool {
self.yes.binary_search(&version).is_ok()
|| (include_partial && self.partial.binary_search(&version).is_ok())
}
}
pub struct Feature {
start: u32,
end: u32,
}
impl Feature {
pub fn new(start: u32, end: u32) -> Self {
Self { start, end }
}
pub fn create_data(&self) -> Vec<(BrowserName, FeatureSet)> {
let table: &'static [String] = super::version_table();
let browser_versions = super::version_orders();
let bytes = &FEATURES.get()[self.start as usize..self.end as usize];
let mut pos = 0;
let entry_count = read_varint(bytes, &mut pos);
let mut data = Vec::with_capacity(entry_count);
for _ in 0..entry_count {
let browser = bytes[pos];
pos += 1;
let order = &browser_versions[browser as usize];
let yes = read_versions(bytes, &mut pos, order, table);
let partial = read_versions(bytes, &mut pos, order, table);
data.push((decode_browser_name(browser), FeatureSet::new(yes, partial)));
}
data
}
}
fn read_versions(
bytes: &[u8],
pos: &mut usize,
order: &[u16],
table: &'static [String],
) -> Vec<&'static str> {
let run_count = read_varint(bytes, pos);
let mut indices = Vec::new();
for _ in 0..run_count {
let start = read_varint(bytes, pos);
let len = read_varint(bytes, pos);
let end = if len == 0 { order.len() } else { start + len };
indices.extend(order[start..end].iter().copied());
}
for i in 1..indices.len() {
let mut j = i;
while j > 0 && indices[j - 1] > indices[j] {
indices.swap(j - 1, j);
j -= 1;
}
}
indices.into_iter().map(|i| table[i as usize].as_str()).collect()
}