use std::collections::HashMap;
use std::sync::OnceLock;
pub const FANTOM_EPOCH_UNIX_SECS: i64 = 946_684_800;
pub const MAX_SAFE_CONST_CODE: i64 = 945;
pub static CONSTS: &[&str] = &[
"", "Obj", "Bin", "Bool", "Coord", "Date", "DateTime", "Dict", "Grid", "List", "Marker", "NA", "Number", "Ref", "Remove", "Span", "Str", "Time", "Uri", "XStr", "Obj[]", "Str[]", "Ref[]", "Dict[]", "UTC", "Rel", "New_York", "Chicago", "Denver", "Los_Angeles", "Phoenix", "Anchorage", "Honolulu", "Halifax", "Winnipeg", "Toronto", "Montreal", "Regina", "Vancouver", "Mexico_City", "Hong_Kong", "Shanghai", "Seoul", "Singapore", "Tokyo", "Kolkata", "Dubai", "Jerusalem", "Sydney", "Melbourne", "Amsterdam", "Berlin", "Brussels", "Copenhagen", "Dublin", "Istanbul", "Lisbon", "London", "Madrid", "Moscow", "Paris", "Stockholm", "Vienna", "Zurich", "unknown", "ok", "down", "fault", "disabled", "stale", "remoteFault", "remoteDown", "remoteDisabled", "remoteUnknown", "pending", "syncing", "unbound", "$siteRef $navName", "$equipRef $navName", "text/plain", "text/javascript", "text/html", "text/trio", "text/zinc", "text/plain; charset=utf-8", "text/javascript; charset=utf-8", "text/html; charset=utf-8", "text/trio; charset=utf-8", "text/zinc; charset=utf-8", "image/gif", "image/jpeg", "image/png", "image/svg", "application/json", "application/octet-stream", "application/pdf", "application/x-dicts", "application/x-his", "absorption", "actions", "ahu", "ahuRef", "air", "airCooled", "alarm", "analytics", "app", "appFormOn", "area", "axAnnotated", "axId", "axSlotPath", "axType", "bacnetConn", "bacnetConnRef", "bacnetCur", "bacnetHis", "bacnetWrite", "bacnetWriteLevel", "blowdown", "boiler", "boilerPlant", "boilerPlantRef", "building", "buildingRef", "bypass", "calendar", "calendarRef", "campusRef", "centrifugal", "chartOn", "chilled", "chilledBeamZone", "chilledWaterCool", "chilledWaterPlant", "chiller", "chillerWaterPlantRef", "circuit", "closedLoop", "cmd", "co", "co2", "coldDeck", "color", "condensate", "condenser", "conn", "connCur", "connErr", "connHis", "connRef", "connState", "connStatus", "connTuning", "connTuningRef", "connWrite", "connection", "constantVolume", "consumption", "cool", "coolOnly", "cooling", "coolingCapacity", "coolingTower", "cost", "cov", "crc", "created", "cur", "curCalibration", "curConvert", "curErr", "curKpi", "curSpark", "curStatus", "curVal", "current", "damper", "date", "delta", "demand", "device", "device1Ref", "device2Ref", "directZone", "dis", "disMacro", "discharge", "domestic", "dualDuct", "ductArea", "dur", "dxCool", "effective", "efficiency", "elec", "elecHeat", "elecMeterLoad", "elecMeterRef", "elecPanel", "elecPanelOf", "elecReheat", "email", "enable", "energy", "entering", "enum", "equip", "equipRef", "evaporator", "exhaust", "ext", "faceBypass", "fan", "fanPowered", "fcu", "filter", "finAsset", "finDependencies", "finFile", "finIcon", "finProject", "finResource", "finRuntime", "finScreenshot", "finThumb", "finUri", "finVersion", "floor", "floorRef", "flow", "folderPath", "formOn", "freezeStat", "freq", "func", "gas", "gasHeat", "gasMeterLoad", "geoAddr", "geoCity", "geoCoord", "geoCountry", "geoCounty", "geoPostalCode", "geoState", "geoStreet", "graphicOn", "haystackConnRef", "haystackCur", "haystackHis", "haystackWrite", "haystackWriteLevel", "haytackConn", "heat", "heatExchanger", "heatPump", "heatWheel", "heating", "help", "helpDoc", "his", "hisCollectCov", "hisCollectInterval", "hisConvert", "hisEnd", "hisEndVal", "hisErr", "hisFunc", "hisId", "hisInterpolate", "hisInterval", "hisKpi", "hisMode", "hisRef", "hisSize", "hisSpark", "hisStart", "hisStatus", "hisTotalized", "hot", "hotDeck", "hotWaterHeat", "hotWaterReheat", "humidifier", "humidity", "hvac", "id", "imageRef", "index", "isolation", "kind", "kpi", "kpiFunc", "kpiOn", "kpiRef", "leaving", "license", "licenseRef", "lightLevel", "lighting", "lights", "lightsGroup", "load", "maint", "maintRef", "makeup", "max", "maxVal", "meter", "min", "minVal", "mixed", "mod", "multiZone", "name", "navName", "network", "networkRef", "neutralDeck", "nextTime", "nextVal", "note", "noteRef", "num", "number", "obixConn", "obixConnRef", "obixCur", "obixHis", "obixWrite", "occ", "occupancyIndicator", "occupied", "openLoop", "order", "orderItem", "orderItemRef", "orderRef", "org", "orgRef", "outside", "parallel", "part", "partRef", "perimeterHeat", "periods", "pf", "phase", "point", "pointRef", "power", "precision", "pressure", "pressureDependent", "pressureIndependent", "primaryFunction", "primaryLoop", "protocol", "pump", "reciprocal", "refrig", "region", "regionRef", "reheat", "reheating", "return", "rooftop", "rule", "ruleFunc", "ruleOn", "ruleRef", "run", "sampled", "schedulable", "schedule", "scheduleRef", "screw", "secondaryLoop", "sensor", "series", "singleDuct", "site", "siteMeter", "sitePanel", "sitePoint", "siteRef", "sp", "space", "spaceRef", "spark", "speed", "src", "stage", "standby", "steam", "steamHeat", "steamMeterLoad", "subPanelOf", "submeterOf", "summary", "sunrise", "supply", "temp", "ticket", "ticketStatus", "times", "tripleDuct", "ts", "tz", "unit", "unocc", "uri", "user", "userRef", "username", "uv", "v0", "v1", "v2", "v3", "v4", "v5", "v7", "v8", "v9", "val", "valve", "variableVolume", "vav", "vavMode", "vavZone", "version", "vfd", "volt", "volume", "water", "waterCooled", "waterMeterLoad", "weather", "weatherCond", "weatherPoint", "weatherRef", "wetBulb", "writable", "writeConvert", "writeErr", "writeLevel", "writeStatus", "writeVal", "yearBuilt", "zone", "zoneRef", "$", "%", "%/s", "%RH", "%obsc/ft", "%obsc/m", "/h", "/min", "/s", "A", "A/m", "A/m²", "AED", "AUD", "Am²", "BTU", "BTU/h", "BTU/lb", "C", "CAD", "COP", "DCIE", "EER", "F", "Fr", "GB", "GJ", "GW", "H", "Hz", "J", "J/g", "J/h", "J/kg", "J/kg_dry", "J/kg°K", "J/m²", "J/°K", "Js", "K", "K/h", "K/min", "K/s", "L", "L/h", "L/min", "L/s", "MB", "MBTU/ft²", "MHz", "MJ", "MJ/ft²", "MJ/h", "MJ/kg_dry", "MJ/m²", "MJ/°K", "MMBTU", "MMBTU/h", "MV", "MVAR", "MVARh", "MVAh", "MW", "MWh", "MWh/ft²", "MWh/m²", "MΩ", "N", "N/m", "NIS", "Nm", "Ns", "PB", "PUE", "Pa", "S", "S/m", "T", "TB", "TWD", "V", "V/K", "V/m", "VA", "VAR", "VARh", "VAh", "W", "W/cfm", "W/ft²", "W/ft²_irr", "W/m°K", "W/m²", "W/m²K", "W/m²_irr", "W/m³/s", "Wb", "Wh", "Wh/ft²", "Wh/m²", "acre", "atm", "bar", "btu/lb_dry", "byte", "cal", "cal/g", "cd", "cd/m²", "cfh", "cfm", "cfs", "cm", "cmHg", "cmH₂O", "cm²", "cm³", "cph", "cpm", "cs", "dBmV", "dBµV", "day", "db", "deg", "degPh", "ds", "fl_oz", "fnu", "ft", "ft/min", "ft/s", "ftcd", "ftlbs/sec", "ft²", "ft³", "ft³_gas", "g", "g/kg", "g/min", "g/m²", "g/s", "gH₂O/kgAir", "gal", "gal/min", "galUK", "galUK/min", "h", "hL", "hL/s", "hPa", "hft³", "hp", "hph", "in", "inHg", "inH₂O", "in²", "in³", "kB", "kBTU", "kBTU/ft²", "kBTU/h", "kBTU/h/ft²", "kHz", "kJ", "kJ/h", "kJ/kg", "kJ/kg_dry", "kJ/°K", "kL", "kPa", "kV", "kVA", "kVAR", "kVARh", "kVAh", "kW", "kW/ft²", "kW/gal/min", "kW/kcfm", "kW/m²", "kW/ton", "kWh", "kWh/ft²", "kWh/m²", "kcfm", "kg", "kg/h", "kg/min", "kg/m²", "kg/m³", "kg/s", "kgal", "klb", "klb/h", "km", "km/h", "km/s", "km²", "knot", "kr", "kΩ", "lb", "lb/h", "lb/min", "lb/s", "lbf", "lm", "lx", "m", "m/h", "m/min", "m/s", "m/s²", "mA", "mL", "mL/s", "mV", "mVA", "mW", "mbar", "mg", "mile", "mile²", "mm", "mm/min", "mm/s", "mmHg", "mm²", "mm³", "mo", "mph", "ms", "m²", "m²/N", "m³", "m³/h", "m³/min", "m³/s", "m³_gas", "mΩ", "ns", "ntu", "oz", "pH", "ppb", "ppm", "ppu", "psi", "psi/°F", "pt", "px", "qt", "rad", "rad/s", "rad/s²", "rpm", "s", "sr", "t", "therm", "therm/h", "ton", "ton/h", "tonref", "tonrefh", "wk", "yd", "yd²", "yd³", "yr", "£", "¥", "°C", "°C/h", "°C/min", "°F", "°F/h", "°F/min", "°daysC", "°daysF", "µg/m³", "µm", "µs", "ΔK", "Δ°C", "Δ°F", "руб", "₩", "€", "₹", "Ω", "Ωm", "元", "accept-charset", "accept-encoding", "accept-language", "all", "auto", "aux", "avg", "baseline", "cache-control", "call", "cells", "children", "clear", "cloudy", "clusterSessionKey", "clusterUsername", "code", "cols", "content", "content-encoding", "content-length", "content-type", "cookie", "dates", "days", "define", "delete", "doc", "equipAccessFilter", "equips", "etag", "eval", "expires", "expr", "extra", "firstName", "flurries", "fold", "get", "group", "groupBy", "gzip", "hasChildren", "head", "headers", "hidden", "hisRollup", "hisRollupDis", "hisRollupInterval", "host", "http", "https", "ice", "icon", "ids", "interval", "keep-alive", "key", "kpiRule", "last-modified", "lastName", "list", "manifest", "map", "mapToHis", "method", "mode", "msg", "msgId", "msgType", "names", "op", "options", "opts", "origin", "partlyCloudy", "pattern", "phrase", "pipe", "pointAccessFilter", "points", "post", "pragma", "priority", "projAccessFilter", "projs", "put", "query", "rain", "read", "readAll", "readById", "readByIds", "referer", "rollup", "rows", "ruleAccessFilter", "ruleType", "rules", "scheme", "sel", "select", "selectable", "server", "showers", "siteAccessFilter", "sites", "snow", "span", "sparkRule", "status", "sum", "targetRef", "targets", "text", "thunderstorms", "timeout", "transfer-encoding", "type", "user-agent", "userAdmin", "userAuthScheme", "view", "viz", "accept", "appName", "base", "batch", "bootId", "bootTime", "charge", "chargeType", "describe", "disKey", "dispatch", "err", "errTrace", "errType", "executeStatus", "executeTime", "find", "findAll", "fingerprint", "flatMap", "folioVersion", "hash", "hisPageSize", "hostId", "hostModel", "inRange", "level", "licProduct", "locale", "masterVer", "maxCount", "maxDataSize", "node", "nodeId", "nonce", "numBlobs", "periodUnion", "ping", "poll", "proj", "pubKey", "push", "range", "rangeStrategy", "ranges", "replicaVer", "req", "res", "route", "routeStatus", "salt", "scheduleVal", "scram", "send", "shape", "SHA-256", "sig", "skyarc-ui-session-key", "spec", "specVer", "stash", "steps", "target", "tariff", "tariffHis", "tariffRef", "trace", "traces", "uiMeta", "usageOn", "useReplica", "userAuth", "userRole", "ver", "admin", "arc", "audit", "by", "clusterAttestKey", "comment", "def", "defx", "file", "input", "is", "item", "items", "of", "parts", "person", "skyarc::UiDef", "skyarc::User", "su", "tagOn", "unknown,clear,partlyCloudy,cloudy,showers,rain,thunderstorms,ice,flurries,snow", "userProto", "userProtoName", "userProtoRef", "airRef", "arcBreakdown", "arcBug", "arcDamage", "arcElectrical", "arcEnhancement", "arcHvac", "arcInspection", "arcMaintenance", "arcOn", "arcPlumbing", "arcPriority", "arcSafety", "arcSupport", "arcWish", "assignedTo", "cancelled", "critical", "dueDate", "elecRef", "high", "low", "medium", "new", "old", "open", "resolved", "ticketState", "viewLink", "weatherStation", "weatherStationRef", "workorder", "workorderState", ];
static CONSTS_MAP: OnceLock<HashMap<&'static str, i64>> = OnceLock::new();
fn consts_map() -> &'static HashMap<&'static str, i64> {
CONSTS_MAP.get_or_init(|| {
CONSTS
.iter()
.enumerate()
.map(|(i, &s)| (s, i as i64))
.collect()
})
}
pub fn lookup_const(s: &str) -> Option<i64> {
let idx = consts_map().get(s).copied()?;
if idx <= MAX_SAFE_CONST_CODE {
Some(idx)
} else {
None
}
}
pub fn get_const(idx: i64) -> Option<&'static str> {
if idx >= 0 && (idx as usize) < CONSTS.len() {
Some(CONSTS[idx as usize])
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_table_length() {
assert_eq!(CONSTS.len(), 1003);
}
#[test]
fn test_index_zero_is_empty_string() {
assert_eq!(CONSTS[0], "");
assert_eq!(lookup_const(""), Some(0));
assert_eq!(get_const(0), Some(""));
}
#[test]
fn test_known_tag_indices() {
assert_eq!(CONSTS[185], "dis");
assert_eq!(CONSTS[382], "site");
assert_eq!(CONSTS[386], "siteRef");
assert_eq!(CONSTS[208], "equipRef");
assert_eq!(CONSTS[408], "ts");
assert_eq!(CONSTS[409], "tz");
assert_eq!(CONSTS[175], "curVal");
assert_eq!(CONSTS[287], "id");
assert_eq!(CONSTS[403], "temp");
}
#[test]
fn test_known_timezone_indices() {
assert_eq!(CONSTS[24], "UTC");
assert_eq!(CONSTS[26], "New_York");
assert_eq!(CONSTS[57], "London");
assert_eq!(CONSTS[44], "Tokyo");
}
#[test]
fn test_known_unit_indices() {
assert_eq!(CONSTS[630], "kW");
assert_eq!(CONSTS[636], "kWh");
assert_eq!(CONSTS[711], "s");
assert_eq!(CONSTS[727], "°C");
assert_eq!(CONSTS[730], "°F");
assert_eq!(CONSTS[563], "cfm");
}
#[test]
fn test_lookup_const_found() {
assert_eq!(lookup_const("dis"), Some(185));
assert_eq!(lookup_const("site"), Some(382));
assert_eq!(lookup_const("UTC"), Some(24));
assert_eq!(lookup_const("kW"), Some(630));
assert_eq!(lookup_const("°F"), Some(730));
}
#[test]
fn test_lookup_const_not_found() {
assert_eq!(lookup_const(""), Some(0));
assert_eq!(lookup_const("notAConst"), None);
}
#[test]
fn test_get_const_valid() {
assert_eq!(get_const(185), Some("dis"));
assert_eq!(get_const(24), Some("UTC"));
assert_eq!(get_const(630), Some("kW"));
assert_eq!(get_const(1002), Some("workorderState"));
}
#[test]
fn test_get_const_invalid() {
assert_eq!(get_const(0), Some(""));
assert_eq!(get_const(-1), None);
assert_eq!(get_const(1003), None);
assert_eq!(get_const(9999), None);
}
#[test]
fn test_lookup_roundtrip() {
for (i, &s) in CONSTS.iter().enumerate() {
if i as i64 <= MAX_SAFE_CONST_CODE {
let idx =
lookup_const(s).unwrap_or_else(|| panic!("Missing const at index {i}: {s:?}"));
assert_eq!(idx, i as i64);
let got = get_const(idx).unwrap();
assert_eq!(got, s);
} else {
assert!(
lookup_const(s).is_none(),
"Expected None for index {i} ({s:?}) above MAX_SAFE_CONST_CODE"
);
assert!(
get_const(i as i64).is_some(),
"get_const({i}) should still work"
);
}
}
}
}