[WIP] Security work While on holiday
This commit is contained in:
parent
a81ac4efca
commit
7f0231e3f1
109 changed files with 19694 additions and 5210 deletions
|
|
@ -2,9 +2,9 @@ use serde::Deserialize;
|
|||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fmt::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::OnceLock;
|
||||
|
||||
const DEFAULT_TYPE_MAPS_PATH: &str = "./type-maps.yaml";
|
||||
const FIRST_USER_TYPE_ID: u16 = 32;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Config {
|
||||
|
|
@ -22,186 +22,54 @@ struct TypeMapConfig {
|
|||
data_types: BTreeMap<String, u16>,
|
||||
}
|
||||
|
||||
struct ReservedEntry {
|
||||
name: &'static str,
|
||||
#[derive(Deserialize)]
|
||||
struct ReservedManifest {
|
||||
#[serde(rename = "firstUserTypeId")]
|
||||
first_user_type_id: u16,
|
||||
communication: Vec<ManifestEntry>,
|
||||
data: Vec<ManifestEntry>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ManifestEntry {
|
||||
name: String,
|
||||
id: u16,
|
||||
}
|
||||
|
||||
const RESERVED_COMM_TYPES: &[ReservedEntry] = &[
|
||||
ReservedEntry {
|
||||
name: "Identification",
|
||||
id: 0,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "IdentificationResponse",
|
||||
id: 1,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Register",
|
||||
id: 2,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "RegisterResponse",
|
||||
id: 3,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Challenge",
|
||||
id: 4,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "ChallengeResponse",
|
||||
id: 5,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Ping",
|
||||
id: 6,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Pong",
|
||||
id: 7,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Disconnect",
|
||||
id: 8,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Redirect",
|
||||
id: 9,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Shutdown",
|
||||
id: 10,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Error",
|
||||
id: 11,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "ErrorParsing",
|
||||
id: 12,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "ErrorBadVersion",
|
||||
id: 13,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "BadRequest",
|
||||
id: 14,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Unauthorized",
|
||||
id: 15,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Forbidden",
|
||||
id: 16,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "NotFound",
|
||||
id: 17,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "TooManyRequests",
|
||||
id: 18,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "InternalServerError",
|
||||
id: 19,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "BadGateway",
|
||||
id: 20,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "ServiceUnavailable",
|
||||
id: 21,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "GatewayTimeout",
|
||||
id: 22,
|
||||
},
|
||||
#[cfg(feature = "pipes")]
|
||||
ReservedEntry {
|
||||
name: "PipeRequest",
|
||||
id: 23,
|
||||
},
|
||||
#[cfg(feature = "pipes")]
|
||||
ReservedEntry {
|
||||
name: "PipeResponse",
|
||||
id: 24,
|
||||
},
|
||||
#[cfg(feature = "pipes")]
|
||||
ReservedEntry {
|
||||
name: "PipeAbort",
|
||||
id: 25,
|
||||
},
|
||||
];
|
||||
fn reserved_manifest() -> &'static ReservedManifest {
|
||||
static MANIFEST: OnceLock<ReservedManifest> = OnceLock::new();
|
||||
MANIFEST.get_or_init(|| {
|
||||
serde_yaml::from_str(include_str!("reserved.json"))
|
||||
.expect("type-map/reserved.json must be valid JSON/YAML")
|
||||
})
|
||||
}
|
||||
|
||||
const RESERVED_DATA_TYPES: &[ReservedEntry] = &[
|
||||
ReservedEntry {
|
||||
name: "Version",
|
||||
id: 0,
|
||||
},
|
||||
ReservedEntry { name: "Id", id: 1 },
|
||||
ReservedEntry {
|
||||
name: "ClientNonce",
|
||||
id: 2,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "ServerNonce",
|
||||
id: 3,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "PublicKeys",
|
||||
id: 4,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Signature",
|
||||
id: 5,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "PqSignature",
|
||||
id: 6,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Description",
|
||||
id: 7,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Connected",
|
||||
id: 8,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Timestamp",
|
||||
id: 9,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Error",
|
||||
id: 10,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "ErrorParsing",
|
||||
id: 11,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "ErrorMessage",
|
||||
id: 12,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "Accepted",
|
||||
id: 13,
|
||||
},
|
||||
ReservedEntry {
|
||||
name: "RequirePq",
|
||||
id: 14,
|
||||
},
|
||||
];
|
||||
fn first_user_type_id() -> u16 {
|
||||
reserved_manifest().first_user_type_id
|
||||
}
|
||||
|
||||
fn all_reserved_comm_types() -> &'static [ManifestEntry] {
|
||||
&reserved_manifest().communication
|
||||
}
|
||||
|
||||
fn generated_reserved_comm_types() -> Vec<&'static ManifestEntry> {
|
||||
all_reserved_comm_types()
|
||||
.iter()
|
||||
.filter(|entry| cfg!(feature = "pipes") || !entry.name.starts_with("Pipe"))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn all_reserved_data_types() -> &'static [ManifestEntry] {
|
||||
&reserved_manifest().data
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let out = PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
||||
let multi_version = std::env::var("CARGO_FEATURE_REGISTRY").is_ok();
|
||||
|
||||
println!("cargo:rerun-if-env-changed=MTP_TYPE_MAPS");
|
||||
println!("cargo:rerun-if-changed=reserved.json");
|
||||
validate_reserved_manifest();
|
||||
|
||||
let loaded = match std::env::var_os("MTP_TYPE_MAPS") {
|
||||
Some(config_path) => load_config(&PathBuf::from(config_path)),
|
||||
|
|
@ -231,6 +99,35 @@ fn main() {
|
|||
std::fs::write(out.join("types.rs"), code).unwrap();
|
||||
}
|
||||
|
||||
fn validate_reserved_manifest() {
|
||||
assert!(first_user_type_id() > 0);
|
||||
for (category, entries) in [
|
||||
("communication", all_reserved_comm_types()),
|
||||
("data", all_reserved_data_types()),
|
||||
] {
|
||||
let mut names = BTreeSet::new();
|
||||
let mut ids = BTreeSet::new();
|
||||
for entry in entries {
|
||||
assert!(
|
||||
entry.id < first_user_type_id(),
|
||||
"reserved {category} type {} has a user-range ID {}",
|
||||
entry.name,
|
||||
entry.id
|
||||
);
|
||||
assert!(
|
||||
names.insert(entry.name.as_str()),
|
||||
"duplicate reserved {category} type name {}",
|
||||
entry.name
|
||||
);
|
||||
assert!(
|
||||
ids.insert(entry.id),
|
||||
"duplicate reserved {category} type ID {}",
|
||||
entry.id
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LoadedConfig {
|
||||
config: Config,
|
||||
path: Option<PathBuf>,
|
||||
|
|
@ -292,8 +189,15 @@ fn validate_config(loaded: &LoadedConfig) {
|
|||
version,
|
||||
"CommunicationTypes",
|
||||
&type_map.communication_types,
|
||||
all_reserved_comm_types(),
|
||||
);
|
||||
validate_ids(
|
||||
loaded,
|
||||
version,
|
||||
"DataTypes",
|
||||
&type_map.data_types,
|
||||
all_reserved_data_types(),
|
||||
);
|
||||
validate_ids(loaded, version, "DataTypes", &type_map.data_types);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -319,16 +223,28 @@ fn validate_ids(
|
|||
version: &str,
|
||||
category: &str,
|
||||
entries: &BTreeMap<String, u16>,
|
||||
reserved: &[ManifestEntry],
|
||||
) {
|
||||
let mut names_by_id = BTreeMap::new();
|
||||
for (name, id) in entries {
|
||||
if *id < FIRST_USER_TYPE_ID {
|
||||
if reserved.iter().any(|entry| entry.name == *name) {
|
||||
validation_error(
|
||||
loaded,
|
||||
&["type_maps", version, category],
|
||||
name,
|
||||
format!(
|
||||
"{category}.{name} in type-map version {version} uses reserved id {id}; user ids must be {FIRST_USER_TYPE_ID} or greater"
|
||||
"{category}.{name} in type-map version {version} uses reserved name {name:?}"
|
||||
),
|
||||
);
|
||||
}
|
||||
if *id < first_user_type_id() {
|
||||
validation_error(
|
||||
loaded,
|
||||
&["type_maps", version, category],
|
||||
name,
|
||||
format!(
|
||||
"{category}.{name} in type-map version {version} uses reserved id {id}; user ids must be {} or greater",
|
||||
first_user_type_id()
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -540,7 +456,7 @@ fn generate_comm_type_enum(out: &mut String, user_names: &BTreeSet<&str>) {
|
|||
writeln!(out, "#[allow(clippy::enum_variant_names)]").unwrap();
|
||||
writeln!(out, "pub enum CommunicationType {{").unwrap();
|
||||
|
||||
for entry in RESERVED_COMM_TYPES {
|
||||
for entry in generated_reserved_comm_types() {
|
||||
writeln!(out, " {},", entry.name).unwrap();
|
||||
}
|
||||
for name in user_names {
|
||||
|
|
@ -554,7 +470,7 @@ fn generate_comm_type_enum(out: &mut String, user_names: &BTreeSet<&str>) {
|
|||
writeln!(out, " pub fn name(self) -> &'static str {{").unwrap();
|
||||
writeln!(out, " match self {{").unwrap();
|
||||
|
||||
for entry in RESERVED_COMM_TYPES {
|
||||
for entry in generated_reserved_comm_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" CommunicationType::{} => \"{}\",",
|
||||
|
|
@ -580,7 +496,7 @@ fn generate_comm_type_enum(out: &mut String, user_names: &BTreeSet<&str>) {
|
|||
writeln!(out, " pub fn from_name(s: &str) -> Option<Self> {{").unwrap();
|
||||
writeln!(out, " match s {{").unwrap();
|
||||
|
||||
for entry in RESERVED_COMM_TYPES {
|
||||
for entry in generated_reserved_comm_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" \"{}\" => Some(CommunicationType::{}),",
|
||||
|
|
@ -625,7 +541,7 @@ fn generate_data_type_enum(out: &mut String, user_names: &BTreeSet<&str>) {
|
|||
writeln!(out, "#[allow(clippy::enum_variant_names)]").unwrap();
|
||||
writeln!(out, "pub enum DataType {{").unwrap();
|
||||
|
||||
for entry in RESERVED_DATA_TYPES {
|
||||
for entry in all_reserved_data_types() {
|
||||
writeln!(out, " {},", entry.name).unwrap();
|
||||
}
|
||||
for name in user_names {
|
||||
|
|
@ -639,7 +555,7 @@ fn generate_data_type_enum(out: &mut String, user_names: &BTreeSet<&str>) {
|
|||
writeln!(out, " pub fn name(self) -> &'static str {{").unwrap();
|
||||
writeln!(out, " match self {{").unwrap();
|
||||
|
||||
for entry in RESERVED_DATA_TYPES {
|
||||
for entry in all_reserved_data_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" DataType::{} => \"{}\",",
|
||||
|
|
@ -660,7 +576,7 @@ fn generate_data_type_enum(out: &mut String, user_names: &BTreeSet<&str>) {
|
|||
writeln!(out, " pub fn from_name(s: &str) -> Option<Self> {{").unwrap();
|
||||
writeln!(out, " match s {{").unwrap();
|
||||
|
||||
for entry in RESERVED_DATA_TYPES {
|
||||
for entry in all_reserved_data_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" \"{}\" => Some(DataType::{}),",
|
||||
|
|
@ -733,7 +649,7 @@ fn generate_lookup_methods(
|
|||
major, minor
|
||||
)
|
||||
.unwrap();
|
||||
for entry in RESERVED_COMM_TYPES {
|
||||
for entry in generated_reserved_comm_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" CommunicationType::{} => Some({}),",
|
||||
|
|
@ -772,7 +688,7 @@ fn generate_lookup_methods(
|
|||
major, minor
|
||||
)
|
||||
.unwrap();
|
||||
for entry in RESERVED_DATA_TYPES {
|
||||
for entry in all_reserved_data_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" DataType::{} => Some({}),",
|
||||
|
|
@ -806,7 +722,7 @@ fn generate_lookup_methods(
|
|||
major, minor
|
||||
)
|
||||
.unwrap();
|
||||
for entry in RESERVED_COMM_TYPES {
|
||||
for entry in generated_reserved_comm_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" {} => Some(CommunicationType::{}),",
|
||||
|
|
@ -844,7 +760,7 @@ fn generate_lookup_methods(
|
|||
major, minor
|
||||
)
|
||||
.unwrap();
|
||||
for entry in RESERVED_DATA_TYPES {
|
||||
for entry in all_reserved_data_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" {} => Some(DataType::{}),",
|
||||
|
|
@ -877,7 +793,7 @@ fn generate_single_version_lookup(out: &mut String, config: &Config) {
|
|||
.unwrap();
|
||||
writeln!(out, " match self.version {{").unwrap();
|
||||
writeln!(out, " PROTOCOL_VERSION => match ct {{").unwrap();
|
||||
for entry in RESERVED_COMM_TYPES {
|
||||
for entry in generated_reserved_comm_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" CommunicationType::{} => Some({}),",
|
||||
|
|
@ -910,7 +826,7 @@ fn generate_single_version_lookup(out: &mut String, config: &Config) {
|
|||
.unwrap();
|
||||
writeln!(out, " match self.version {{").unwrap();
|
||||
writeln!(out, " PROTOCOL_VERSION => match dt {{").unwrap();
|
||||
for entry in RESERVED_DATA_TYPES {
|
||||
for entry in all_reserved_data_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" DataType::{} => Some({}),",
|
||||
|
|
@ -938,7 +854,7 @@ fn generate_single_version_lookup(out: &mut String, config: &Config) {
|
|||
.unwrap();
|
||||
writeln!(out, " match self.version {{").unwrap();
|
||||
writeln!(out, " PROTOCOL_VERSION => match id {{").unwrap();
|
||||
for entry in RESERVED_COMM_TYPES {
|
||||
for entry in generated_reserved_comm_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" {} => Some(CommunicationType::{}),",
|
||||
|
|
@ -970,7 +886,7 @@ fn generate_single_version_lookup(out: &mut String, config: &Config) {
|
|||
.unwrap();
|
||||
writeln!(out, " match self.version {{").unwrap();
|
||||
writeln!(out, " PROTOCOL_VERSION => match id {{").unwrap();
|
||||
for entry in RESERVED_DATA_TYPES {
|
||||
for entry in all_reserved_data_types() {
|
||||
writeln!(
|
||||
out,
|
||||
" {} => Some(DataType::{}),",
|
||||
|
|
@ -1077,7 +993,7 @@ fn generate_all_types_methods(
|
|||
let tm_cfg = &config.type_maps[version_key];
|
||||
write!(out, " Version({}, {}) => &[", major, minor).unwrap();
|
||||
let mut first = true;
|
||||
for entry in RESERVED_COMM_TYPES {
|
||||
for entry in generated_reserved_comm_types() {
|
||||
if !first {
|
||||
write!(out, ", ").unwrap();
|
||||
}
|
||||
|
|
@ -1108,7 +1024,7 @@ fn generate_all_types_methods(
|
|||
let tm_cfg = &config.type_maps[version_key];
|
||||
write!(out, " Version({}, {}) => &[", major, minor).unwrap();
|
||||
let mut first = true;
|
||||
for entry in RESERVED_DATA_TYPES {
|
||||
for entry in all_reserved_data_types() {
|
||||
if !first {
|
||||
write!(out, ", ").unwrap();
|
||||
}
|
||||
|
|
@ -1144,7 +1060,7 @@ fn generate_all_types_methods_single(out: &mut String, config: &Config) {
|
|||
writeln!(out, " match self.version {{").unwrap();
|
||||
write!(out, " PROTOCOL_VERSION => &[").unwrap();
|
||||
let mut first = true;
|
||||
for entry in RESERVED_COMM_TYPES {
|
||||
for entry in generated_reserved_comm_types() {
|
||||
if !first {
|
||||
write!(out, ", ").unwrap();
|
||||
}
|
||||
|
|
@ -1174,7 +1090,7 @@ fn generate_all_types_methods_single(out: &mut String, config: &Config) {
|
|||
writeln!(out, " match self.version {{").unwrap();
|
||||
write!(out, " PROTOCOL_VERSION => &[").unwrap();
|
||||
let mut first = true;
|
||||
for entry in RESERVED_DATA_TYPES {
|
||||
for entry in all_reserved_data_types() {
|
||||
if !first {
|
||||
write!(out, ", ").unwrap();
|
||||
}
|
||||
|
|
|
|||
57
type-map/reserved.json
Normal file
57
type-map/reserved.json
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"firstUserTypeId": 32,
|
||||
"communication": [
|
||||
{ "name": "Identification", "id": 0 },
|
||||
{ "name": "IdentificationResponse", "id": 1 },
|
||||
{ "name": "Register", "id": 2 },
|
||||
{ "name": "RegisterResponse", "id": 3 },
|
||||
{ "name": "Challenge", "id": 4 },
|
||||
{ "name": "ChallengeResponse", "id": 5 },
|
||||
{ "name": "Ping", "id": 6 },
|
||||
{ "name": "Pong", "id": 7 },
|
||||
{ "name": "Disconnect", "id": 8 },
|
||||
{ "name": "Redirect", "id": 9 },
|
||||
{ "name": "Shutdown", "id": 10 },
|
||||
{ "name": "Error", "id": 11 },
|
||||
{ "name": "ErrorParsing", "id": 12 },
|
||||
{ "name": "ErrorBadVersion", "id": 13 },
|
||||
{ "name": "BadRequest", "id": 14 },
|
||||
{ "name": "Unauthorized", "id": 15 },
|
||||
{ "name": "Forbidden", "id": 16 },
|
||||
{ "name": "NotFound", "id": 17 },
|
||||
{ "name": "TooManyRequests", "id": 18 },
|
||||
{ "name": "InternalServerError", "id": 19 },
|
||||
{ "name": "BadGateway", "id": 20 },
|
||||
{ "name": "ServiceUnavailable", "id": 21 },
|
||||
{ "name": "GatewayTimeout", "id": 22 },
|
||||
{ "name": "PipeRequest", "id": 23 },
|
||||
{ "name": "PipeResponse", "id": 24 },
|
||||
{ "name": "PipeAbort", "id": 25 },
|
||||
{ "name": "Relay", "id": 26 }
|
||||
],
|
||||
"data": [
|
||||
{ "name": "Version", "id": 0 },
|
||||
{ "name": "Id", "id": 1 },
|
||||
{ "name": "ClientNonce", "id": 2 },
|
||||
{ "name": "ServerNonce", "id": 3 },
|
||||
{ "name": "PublicKeys", "id": 4 },
|
||||
{ "name": "Signature", "id": 5 },
|
||||
{ "name": "PqSignature", "id": 6 },
|
||||
{ "name": "Description", "id": 7 },
|
||||
{ "name": "Connected", "id": 8 },
|
||||
{ "name": "Timestamp", "id": 9 },
|
||||
{ "name": "Error", "id": 10 },
|
||||
{ "name": "ErrorParsing", "id": 11 },
|
||||
{ "name": "ErrorMessage", "id": 12 },
|
||||
{ "name": "Accepted", "id": 13 },
|
||||
{ "name": "RequirePq", "id": 14 },
|
||||
{ "name": "MessageId", "id": 15 },
|
||||
{ "name": "FinalRecipientId", "id": 18 },
|
||||
{ "name": "CreatedAt", "id": 21 },
|
||||
{ "name": "MessageType", "id": 22 },
|
||||
{ "name": "Content", "id": 23 },
|
||||
{ "name": "Metadata", "id": 24 },
|
||||
{ "name": "RelayVersion", "id": 25 },
|
||||
{ "name": "ProtectedVersion", "id": 26 }
|
||||
]
|
||||
}
|
||||
|
|
@ -92,6 +92,51 @@ impl TypeMap {
|
|||
|
||||
include!(concat!(env!("OUT_DIR"), "/types.rs"));
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{DataType, TypeMap};
|
||||
|
||||
#[test]
|
||||
fn current_relay_reserved_fields_use_generic_layout() {
|
||||
let type_map = TypeMap::latest();
|
||||
|
||||
assert_eq!(
|
||||
DataType::MessageId.try_to_id(&type_map).map(|id| id.0),
|
||||
Some(15)
|
||||
);
|
||||
assert_eq!(
|
||||
DataType::FinalRecipientId
|
||||
.try_to_id(&type_map)
|
||||
.map(|id| id.0),
|
||||
Some(18)
|
||||
);
|
||||
assert_eq!(
|
||||
DataType::CreatedAt.try_to_id(&type_map).map(|id| id.0),
|
||||
Some(21)
|
||||
);
|
||||
assert_eq!(
|
||||
DataType::MessageType.try_to_id(&type_map).map(|id| id.0),
|
||||
Some(22)
|
||||
);
|
||||
assert_eq!(
|
||||
DataType::Content.try_to_id(&type_map).map(|id| id.0),
|
||||
Some(23)
|
||||
);
|
||||
assert_eq!(
|
||||
DataType::Metadata.try_to_id(&type_map).map(|id| id.0),
|
||||
Some(24)
|
||||
);
|
||||
assert_eq!(
|
||||
DataType::RelayVersion.try_to_id(&type_map).map(|id| id.0),
|
||||
Some(25)
|
||||
);
|
||||
|
||||
for tombstoned_id in [16, 17, 19, 20] {
|
||||
assert_eq!(type_map.data_type_name(tombstoned_id), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================= REGISTRY ============================= */
|
||||
#[cfg(feature = "registry")]
|
||||
pub use registry::*;
|
||||
|
|
@ -169,9 +214,17 @@ mod registry {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn builtin_contains_versions() {
|
||||
fn builtin_registers_only_the_current_codec_version() {
|
||||
let r = Registry::builtin();
|
||||
assert!(r.supports(&Version(0, 0)));
|
||||
assert!(r.supports(&Version(3, 0)));
|
||||
for removed_version in [Version(0, 0), Version(1, 0), Version(2, 0)] {
|
||||
assert!(!r.supports(&removed_version));
|
||||
assert_eq!(r.negotiate(&[removed_version]), None);
|
||||
}
|
||||
assert_eq!(
|
||||
r.negotiate(&[Version(3, 0), Version(2, 0)]),
|
||||
Some(Version(3, 0))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in a new issue