#[path = "signing/signing.rs"]
mod signing;
use std::fmt;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FrameworkId(pub &'static str);
impl FrameworkId {
pub const fn new(value: &'static str) -> Self {
Self(value)
}
}
impl fmt::Display for FrameworkId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.0)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ContractId(pub &'static str);
impl ContractId {
pub const NONE: Self = Self("");
pub const fn new(value: &'static str) -> Self {
Self(value)
}
}
impl fmt::Display for ContractId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.0)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct FlowContract {
pub id: ContractId,
pub version: u32,
pub input: &'static str,
pub output: &'static str,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OwnedFlowContract {
pub id: String,
pub version: u32,
pub input: String,
pub output: String,
}
impl OwnedFlowContract {
pub fn none() -> Self {
Self {
id: String::new(),
version: 0,
input: String::new(),
output: String::new(),
}
}
pub fn is_declared(&self) -> bool {
flow_is_declared(&self.id)
}
pub fn semantically_compatible_with(&self, expected: &Self) -> bool {
let left = FlowFields::from_owned(self);
let right = FlowFields::from_owned(expected);
flow_fields_equal(left, right) || flow_fields_semantically_compatible(left, right)
}
}
impl From<FlowContract> for OwnedFlowContract {
fn from(contract: FlowContract) -> Self {
Self {
id: contract.id.0.to_owned(),
version: contract.version,
input: contract.input.to_owned(),
output: contract.output.to_owned(),
}
}
}
impl fmt::Display for OwnedFlowContract {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"{} v{} ({} -> {})",
self.id, self.version, self.input, self.output
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FlowSemantic {
Unknown,
LocalCoordinates,
AbsoluteCoordinates,
LogicalPixels,
PhysicalPixels,
}
impl FlowContract {
pub const NONE: Self = Self {
id: ContractId::NONE,
version: 0,
input: "",
output: "",
};
pub const fn new(
id: ContractId,
version: u32,
input: &'static str,
output: &'static str,
) -> Self {
Self {
id,
version,
input,
output,
}
}
pub const fn is_declared(self) -> bool {
flow_is_declared(self.id.0)
}
pub fn compatible_with(self, expected: Self) -> bool {
flow_fields_equal(
FlowFields::from_declared(self),
FlowFields::from_declared(expected),
)
}
pub fn input_semantic(self) -> FlowSemantic {
flow_semantic(self.input)
}
pub fn output_semantic(self) -> FlowSemantic {
flow_semantic(self.output)
}
pub fn semantically_compatible_with(self, expected: Self) -> bool {
let left = FlowFields::from_declared(self);
let right = FlowFields::from_declared(expected);
flow_fields_equal(left, right) || flow_fields_semantically_compatible(left, right)
}
}
#[derive(Clone, Copy)]
struct FlowFields<'a> {
id: &'a str,
version: u32,
input: &'a str,
output: &'a str,
}
impl<'a> FlowFields<'a> {
fn from_declared(contract: FlowContract) -> Self {
Self {
id: contract.id.0,
version: contract.version,
input: contract.input,
output: contract.output,
}
}
fn from_owned(contract: &'a OwnedFlowContract) -> Self {
Self {
id: &contract.id,
version: contract.version,
input: &contract.input,
output: &contract.output,
}
}
}
const fn flow_is_declared(id: &str) -> bool {
!id.is_empty()
}
fn flow_fields_equal(left: FlowFields<'_>, right: FlowFields<'_>) -> bool {
left.id == right.id
&& left.version == right.version
&& left.input == right.input
&& left.output == right.output
}
fn flow_fields_semantically_compatible(left: FlowFields<'_>, right: FlowFields<'_>) -> bool {
left.id == right.id
&& left.version == right.version
&& labels_compatible(left.input, right.input)
&& labels_compatible(left.output, right.output)
}
fn labels_compatible(left: &str, right: &str) -> bool {
match (flow_semantic(left), flow_semantic(right)) {
(FlowSemantic::Unknown, FlowSemantic::Unknown) => left == right,
(FlowSemantic::Unknown, _) | (_, FlowSemantic::Unknown) => false,
(left, right) => left == right,
}
}
fn flow_semantic(value: &str) -> FlowSemantic {
if value == "LocalCoordinates" || value == "local_coordinates" {
FlowSemantic::LocalCoordinates
} else if value == "AbsoluteCoordinates" || value == "absolute_coordinates" {
FlowSemantic::AbsoluteCoordinates
} else if value == "LogicalPixels" || value == "logical_pixels" {
FlowSemantic::LogicalPixels
} else if value == "PhysicalPixels" || value == "physical_pixels" {
FlowSemantic::PhysicalPixels
} else {
FlowSemantic::Unknown
}
}
pub trait FlowContractProvider {
const FLOW_CONTRACT: FlowContract;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum PluginMode {
Extension,
Replacement,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum PluginSource {
Official,
User,
}
impl PluginSource {
#[doc(hidden)]
pub fn parse(value: &str) -> Option<Self> {
match value {
"official" => Some(Self::Official),
"user" => Some(Self::User),
_ => None,
}
}
}
impl PluginMode {
#[doc(hidden)]
pub fn parse(value: &str) -> Option<Self> {
match value {
"extension" => Some(Self::Extension),
"replacement" => Some(Self::Replacement),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PluginManifest {
pub name: &'static str,
pub crate_name: &'static str,
pub version: &'static str,
pub framework: FrameworkId,
pub source: PluginSource,
pub mode: PluginMode,
pub checksum: &'static str,
pub signature: Option<&'static str>,
pub public_key_fingerprint: Option<&'static str>,
pub revocation_list: Option<&'static str>,
}
impl PluginManifest {
pub fn targets(self, framework: FrameworkId) -> bool {
self.framework.0 == framework.0
}
pub fn verify_bytes(self, bytes: &[u8]) -> bool {
let expected = self
.checksum
.strip_prefix("sha256:")
.unwrap_or(self.checksum);
expected.len() == 64 && crate::sha256_hex(bytes).eq_ignore_ascii_case(expected)
}
pub fn signing_payload(self, registration: &crate::RegistrationInfo, bytes: &[u8]) -> Vec<u8> {
let mut payload = Vec::with_capacity(bytes.len() + 512);
signing::manifest(&mut payload, self);
signing::registration(registration, &mut payload);
payload.extend_from_slice(&(bytes.len() as u64).to_le_bytes());
payload.extend_from_slice(bytes);
payload
}
}
#[cfg(test)]
mod flow_label_tests {
use super::{ContractId, FlowContract, OwnedFlowContract};
#[test]
fn unknown_output_labels_must_agree_literally() {
let target = FlowContract::new(
ContractId::new("render.v1"),
1,
"LocalCoordinates",
"CanvasFrame",
);
let different = FlowContract::new(
ContractId::new("render.v1"),
1,
"LocalCoordinates",
"TotallyDifferentType",
);
assert!(!target.semantically_compatible_with(different));
assert!(target.semantically_compatible_with(target));
}
#[test]
fn known_domains_keep_accepting_spelling_differences() {
let target = FlowContract::new(
ContractId::new("render.v1"),
1,
"LocalCoordinates",
"CanvasFrame",
);
let respelled = FlowContract::new(
ContractId::new("render.v1"),
1,
"local_coordinates",
"CanvasFrame",
);
assert!(target.semantically_compatible_with(respelled));
let respelled_with_other_output = FlowContract::new(
ContractId::new("render.v1"),
1,
"local_coordinates",
"TotallyDifferentType",
);
assert!(!target.semantically_compatible_with(respelled_with_other_output));
}
#[test]
fn static_and_owned_flow_contracts_compare_identically() {
let cases = [
("render.v1", 1, "LocalCoordinates", "CanvasFrame"),
("render.v1", 1, "local_coordinates", "CanvasFrame"),
("render.v1", 1, "LocalCoordinates", "TotallyDifferentType"),
("render.v1", 2, "LocalCoordinates", "CanvasFrame"),
("render.v2", 1, "LocalCoordinates", "CanvasFrame"),
("", 0, "", ""),
];
for &(id, version, input, output) in &cases {
for &(other_id, other_version, other_input, other_output) in &cases {
let left = FlowContract::new(ContractId::new(id), version, input, output);
let right = FlowContract::new(
ContractId::new(other_id),
other_version,
other_input,
other_output,
);
let owned_left = OwnedFlowContract::from(left);
let owned_right = OwnedFlowContract::from(right);
assert_eq!(
left.is_declared(),
owned_left.is_declared(),
"is_declared disagrees for {left:?}"
);
assert_eq!(
left.compatible_with(right),
owned_left == owned_right,
"literal comparison disagrees for {left:?} vs {right:?}"
);
assert_eq!(
left.semantically_compatible_with(right),
owned_left.semantically_compatible_with(&owned_right),
"semantic comparison disagrees for {left:?} vs {right:?}"
);
}
}
}
#[test]
fn compatible_with_stays_literal_while_the_semantic_entry_point_folds_spellings() {
let literal = FlowContract::new(
ContractId::new("render.v1"),
1,
"LocalCoordinates",
"CanvasFrame",
);
let respelled = FlowContract::new(
ContractId::new("render.v1"),
1,
"local_coordinates",
"CanvasFrame",
);
assert!(
!literal.compatible_with(respelled),
"compatible_with must stay a literal comparison"
);
assert!(
literal.semantically_compatible_with(respelled),
"the semantic entry point folds known-domain spellings"
);
assert_eq!(
literal.compatible_with(respelled),
OwnedFlowContract::from(literal) == OwnedFlowContract::from(respelled)
);
assert_eq!(
literal.semantically_compatible_with(respelled),
OwnedFlowContract::from(literal)
.semantically_compatible_with(&OwnedFlowContract::from(respelled))
);
}
}