diff --git a/crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.json b/crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.json index 300f49a0..58f94b2a 100644 --- a/crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.json +++ b/crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.json @@ -6,11 +6,11 @@ }, "artifacts": [ { - "bytes": 85430, + "bytes": 87048, "license": "MIT", "path": "crates/labcolors-core/src/appearance.rs", "role": "appearance_executor_source", - "sha256": "019899f04cf91a29e4710609cd8d8c334784833a0972204cfedb179517a1e732" + "sha256": "d31c6a7d3b0a4c02532759befaef442e3a99687263a9027771365638b6cc3324" }, { "bytes": 6373, @@ -104,11 +104,11 @@ "sha256": "8f0366079e6fa0006360ab19b0449e622add48fdb08431a02258236e1371d78a" }, { - "bytes": 168354, + "bytes": 168536, "license": "MIT", "path": "crates/labcolors-core/src/program_session.rs", "role": "program_source", - "sha256": "6b418c3988626c7037479feed1047134e3209e59c7c5c65b5d3ad9cbdeaa38d9" + "sha256": "8ff19a493171c5437066b8ce489c1925e26f93b4981ad4f1c0ac88461e90eab9" }, { "bytes": 21546, diff --git a/crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.sha256 b/crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.sha256 index 62f79f8d..5c00236f 100644 --- a/crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.sha256 +++ b/crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.sha256 @@ -1 +1 @@ -e278f39f2659dee0ddfe81f416fabcbe3c25018abfea9e8cbfa65ceec3222c21 receipt-v1.json +2cdb16116e01efd9d76bff544e1b13dac1cc9a59208bf5ad5f42808c1e024cc0 receipt-v1.json diff --git a/crates/labcolors-core/contracts/point-support-reference-surplus-q55-bps-proof-v1.json b/crates/labcolors-core/contracts/point-support-reference-surplus-q55-bps-proof-v1.json index 57849677..5ae15e3c 100644 --- a/crates/labcolors-core/contracts/point-support-reference-surplus-q55-bps-proof-v1.json +++ b/crates/labcolors-core/contracts/point-support-reference-surplus-q55-bps-proof-v1.json @@ -1 +1 @@ -{"artifact_id":"wcag22-srgb8-luminance-q55-v1","basis_point_proof":{"checks":30,"drop_all_semantics":"zero required surplus; current must still meet the anchor","drop_domain_inclusive":[0,10000],"nonpositive_baseline_semantics":"zero required surplus; current must meet the anchor"},"bound_id":"point-support-reference-surplus-q55-bps-v1","certified_claim":"for every successfully evaluated enabled stability cell, decision is Retained iff current_lower_surplus >= (10000-drop_bps)/10000 * max(baseline_lower_surplus,0); the declared anchor remains a separate hard floor","comparator_proof":{"algorithm":"euclidean-continued-fraction-ordering-v1","dense_denominator_inclusive":[1,31],"dense_numerator_inclusive":[0,31],"dense_small_cases":984064,"invariant":"equal integer parts; reciprocal proper fractions reverse order","largest_fibonacci_index":186,"oracle":"unbounded-integer-cross-product","random_cases":250000,"random_corpus_sha256":"97c4af7b452b31a4ab92645f70c17acb38bf57ca55484e32ad9d7d79d97a333d","random_seed":210583930,"termination":"each nonterminal denominator becomes a strictly smaller remainder","u128_adversarial_cases":190},"declared_operation_law":"q55-lower-reference-distance-explicit-anchor-bps-retention-v1","excluded_claim":"does not certify retention against the unknown exact baseline surplus, renderer equivalence outside encoded-sRGB8 source-over, or a successful result when evaluation fails","integer_replay_envelope":{"assumption":"every Q55 luminance upper <= scale + 3","i128_max":170141183460469231731687303715884105727,"offset_cleared_denominator_max":756604737398243388,"positive_baseline_numerator_max":1188950301625811064,"rational_denominator_max":1513209474796486776,"required_denominator_max":15132094747964867760000,"required_numerator_max":11889503016258110640000,"signed_anchor_abs_coarse_max":5296233161787703716,"u128_max":340282366920938463463374607431768211455,"u64_max":18446744073709551615},"profile_id":"srgb8-q55-retained-reference-surplus-bps-v1","proof_id":"point-support-reference-surplus-integer-v1","proof_payload_sha256":"89457a39c51a6d3ff82a205b137902a01e3154328df90110573cee1f4287befb","q55_dependency":{"artifact_id":"wcag22-srgb8-luminance-q55-v1","artifact_sha256":"7ff239d9052b346f3c50da01ca65ca2330892ed1a3ff30e190797fcef6f03604","maximum_luminance_upper":36028797018963971,"outward_interval_width_bound":3,"proof_id":"wcag22-srgb8-full-domain-q55-v1","proof_payload_sha256":"3c639a7c875046c46b56b51ecdd67d5ecaf14a1134490c88a222e7037b63c0f2","proof_sha256":"ac59cf89503170c789223b91d775213a19d4e571ef930f2ea609fcd51b14defd","q55_scale":36028797018963968},"reference_and_anchor_proof":{"anchor_identity_checks":75,"orientation_law":"distance-magnitude-symmetric-orientation-reported-separately","overlap_lower_distance":"0/1","separated_endpoint_checks":504},"schema_version":2,"site_id":"point-support-retained-reference-surplus-v1","source_binding_exclusions":["whole-crate compilation or compiler/toolchain attestation","binary, package, FFI, renderer, or browser transport attestation","unrelated Lab Colors modules outside the declared point-support semantic cone"],"source_binding_law":"point-support-rust-whole-file-semantic-cone-v2","source_binding_schema_version":2,"source_binding_scope":"exact bytes of the private point-support Rust semantic cone and its two WCAG include_str inputs; comments and cfg(test) text are intentionally significant","source_closure_sha256":"472d7e40538fc8864b66ddc65ab45728183b3a8cd309efa49011f3ce2b9f6619","source_files":[{"kind":"compile-time-input","path":"crates/labcolors-core/contracts/wcag22-srgb8-q55-proof-v1.json","sha256":"ac59cf89503170c789223b91d775213a19d4e571ef930f2ea609fcd51b14defd"},{"kind":"compile-time-input","path":"crates/labcolors-core/contracts/wcag22-srgb8-v1.json","sha256":"b4bb7e5f17a99f2c911fdbe3da23a48b049277b796291094950f14680cc3cc7b"},{"kind":"rust-source","path":"crates/labcolors-core/src/appearance.rs","sha256":"019899f04cf91a29e4710609cd8d8c334784833a0972204cfedb179517a1e732"},{"kind":"rust-source","path":"crates/labcolors-core/src/composition.rs","sha256":"195a67327a3bd86d7816b634481389930bf68577bb1202fad14c2ea152df8625"},{"kind":"rust-source","path":"crates/labcolors-core/src/constraints/exact.rs","sha256":"892576a8621185352583e63dc0a1aacac32e32a8063b6fe24ae16d4ff9dce7cb"},{"kind":"rust-source","path":"crates/labcolors-core/src/constraints/mod.rs","sha256":"aba84c05a203af12ef2e445334409d9bd385a854c9058f0e30bbf8542addddbc"},{"kind":"rust-source","path":"crates/labcolors-core/src/constraints/wcag22.rs","sha256":"856093c91159d8b3faab001f2d6524d33d7b16458a5a4e98ea65f8c62ab2694c"},{"kind":"rust-source","path":"crates/labcolors-core/src/hash.rs","sha256":"f97a0fd7d6ad3162f0f1dfb326fccfb7ed40da9a8fa67a5b8a239a1ae2ae49c3"},{"kind":"rust-source","path":"crates/labcolors-core/src/lcs_occurrence.rs","sha256":"78d37406e9bdc37f126b72987c9c92b452c13b3233c0aeb0a75ed25dadb83a68"},{"kind":"rust-source","path":"crates/labcolors-core/src/lib.rs","sha256":"b30300edd3910e3d9da1e56896ce14c3db508b1a6fc5608e01032a5ad95777b1"},{"kind":"rust-source","path":"crates/labcolors-core/src/numerics.rs","sha256":"e73a12136494f2ef9aca4e943ab38302c1439f054cecab36a552d35252c164f9"},{"kind":"rust-source","path":"crates/labcolors-core/src/observation.rs","sha256":"d31f5d5f95fbb2300c90899a26905c3cd2804be7c0e9290999005fd9e2c8f6d6"},{"kind":"rust-source","path":"crates/labcolors-core/src/point_support.rs","sha256":"6f6a376ff036d3d65960c004e6566e1bca580f19f5bd3cd333a80b0da5b5c242"},{"kind":"rust-source","path":"crates/labcolors-core/src/session.rs","sha256":"c7a1706ad4837adfdfbe58a302d20b613912530ebff260fd877a47210b02ef46"},{"kind":"rust-source","path":"crates/labcolors-core/src/srgb8.rs","sha256":"6c95324eb05476f35f75375a9af0b2b4a41b8b2978c46e67d2ce1aea5adde342"},{"kind":"rust-source","path":"crates/labcolors-core/src/wcag22.rs","sha256":"7ba7864eb7e73789bad6c63c64a4dc2dcc08c2da6921375fb9564fca230c2780"},{"kind":"rust-source","path":"crates/labcolors-core/src/wcag22/kernel.rs","sha256":"c97980c1ca2c7ea9cabff9c8d2fb7282773cca180ae15948391c29c9d6196040"},{"kind":"rust-source","path":"crates/labcolors-core/src/wcag22/q55_data.rs","sha256":"af4d23d6b70c45ce6efa839e7dda4bb0a61f6aae43cb805af6fa9b29e6c3bae2"},{"kind":"rust-source","path":"crates/labcolors-core/src/wcag22_evidence.rs","sha256":"3c5a75b07254c6071a64700af208a64987d0f0ea9698eadc54a9e74585ce1f72"}],"source_negative_controls":43,"universal_algebraic_certificate":{"basis_point_scale_instantiation":10000,"domain":"integers; Q55 scale Q>0; anchor L>=D>=0; lighter monotonicity L2>=L1>D>=0; darker monotonicity L>D2>=D1>=0; current/baseline denominators b,q>0; basis-point scale B>0 instantiated as 10000; p>0; a>=0; 0<=drop_bps<=B","identities":["three explicit anchor-surplus formulas after denominator clearing","reference distance is monotone increasing in lighter L","reference distance is monotone decreasing in darker D","positive-baseline retained threshold is p*(B-drop)/(q*B)","a/b >= p*(B-drop)/(q*B) iff a*q*B >= p*(B-drop)*b"],"method":"exact-sparse-integer-polynomial-identities-plus-positive-denominator-order-lemma-v1","nonpositive_baseline_case":"max(baseline,0)=0; retained threshold is exactly zero","symbolic_mutation_controls":{"anchor_coefficients_and_denominator":6,"retained_cross_product":5},"wolfram_language_cross_check":{"query":"FullSimplify[{20 g/d - 0 == 20 g/d, 20 g/d - 2 == (20 g - 2 d)/d, 20 g/d - 7/2 == (40 g - 7 d)/(2 d), Equivalent[a/b >= p (s-x)/(q s), a q s >= p (s-x) b], Max[p/q, 0] (s-x)/s == Piecewise[{{0, p <= 0}}, p (s-x)/(q s)]}, Assumptions -> Element[{a,b,p,q,s,x,g,d}, Integers] && a >= 0 && b > 0 && q > 0 && s > 0 && 0 <= x <= s && d > 0 && g >= 0]","query_sha256":"8cdbb9964583030c8b92498961896cb2a98613f1cb31eb7c54acdf8e16beff10","result":"{True, True, True, True, True}","result_sha256":"13a8f2ee8d0fde335a638e46d7cc8a8427b9a1437c77d22cfcf925bb87fa6303"}},"verifier_sha256":"7607cc9b4ff7ecc78a3b9ae07d16c952055b5b0e2c2da0c5dbb9d5d180962bc9"} +{"artifact_id":"wcag22-srgb8-luminance-q55-v1","basis_point_proof":{"checks":30,"drop_all_semantics":"zero required surplus; current must still meet the anchor","drop_domain_inclusive":[0,10000],"nonpositive_baseline_semantics":"zero required surplus; current must meet the anchor"},"bound_id":"point-support-reference-surplus-q55-bps-v1","certified_claim":"for every successfully evaluated enabled stability cell, decision is Retained iff current_lower_surplus >= (10000-drop_bps)/10000 * max(baseline_lower_surplus,0); the declared anchor remains a separate hard floor","comparator_proof":{"algorithm":"euclidean-continued-fraction-ordering-v1","dense_denominator_inclusive":[1,31],"dense_numerator_inclusive":[0,31],"dense_small_cases":984064,"invariant":"equal integer parts; reciprocal proper fractions reverse order","largest_fibonacci_index":186,"oracle":"unbounded-integer-cross-product","random_cases":250000,"random_corpus_sha256":"97c4af7b452b31a4ab92645f70c17acb38bf57ca55484e32ad9d7d79d97a333d","random_seed":210583930,"termination":"each nonterminal denominator becomes a strictly smaller remainder","u128_adversarial_cases":190},"declared_operation_law":"q55-lower-reference-distance-explicit-anchor-bps-retention-v1","excluded_claim":"does not certify retention against the unknown exact baseline surplus, renderer equivalence outside encoded-sRGB8 source-over, or a successful result when evaluation fails","integer_replay_envelope":{"assumption":"every Q55 luminance upper <= scale + 3","i128_max":170141183460469231731687303715884105727,"offset_cleared_denominator_max":756604737398243388,"positive_baseline_numerator_max":1188950301625811064,"rational_denominator_max":1513209474796486776,"required_denominator_max":15132094747964867760000,"required_numerator_max":11889503016258110640000,"signed_anchor_abs_coarse_max":5296233161787703716,"u128_max":340282366920938463463374607431768211455,"u64_max":18446744073709551615},"profile_id":"srgb8-q55-retained-reference-surplus-bps-v1","proof_id":"point-support-reference-surplus-integer-v1","proof_payload_sha256":"5452b758c6b38634e13786164109205d002a4ecc51965b823a5a7354e5ea46eb","q55_dependency":{"artifact_id":"wcag22-srgb8-luminance-q55-v1","artifact_sha256":"7ff239d9052b346f3c50da01ca65ca2330892ed1a3ff30e190797fcef6f03604","maximum_luminance_upper":36028797018963971,"outward_interval_width_bound":3,"proof_id":"wcag22-srgb8-full-domain-q55-v1","proof_payload_sha256":"3c639a7c875046c46b56b51ecdd67d5ecaf14a1134490c88a222e7037b63c0f2","proof_sha256":"ac59cf89503170c789223b91d775213a19d4e571ef930f2ea609fcd51b14defd","q55_scale":36028797018963968},"reference_and_anchor_proof":{"anchor_identity_checks":75,"orientation_law":"distance-magnitude-symmetric-orientation-reported-separately","overlap_lower_distance":"0/1","separated_endpoint_checks":504},"schema_version":2,"site_id":"point-support-retained-reference-surplus-v1","source_binding_exclusions":["whole-crate compilation or compiler/toolchain attestation","binary, package, FFI, renderer, or browser transport attestation","unrelated Lab Colors modules outside the declared point-support semantic cone"],"source_binding_law":"point-support-rust-whole-file-semantic-cone-v2","source_binding_schema_version":2,"source_binding_scope":"exact bytes of the private point-support Rust semantic cone and its two WCAG include_str inputs; comments and cfg(test) text are intentionally significant","source_closure_sha256":"de9e26c5da5d24cd1a76092c5e5caea02fe69f1f18d367fbf0ea7635bee819a9","source_files":[{"kind":"compile-time-input","path":"crates/labcolors-core/contracts/wcag22-srgb8-q55-proof-v1.json","sha256":"ac59cf89503170c789223b91d775213a19d4e571ef930f2ea609fcd51b14defd"},{"kind":"compile-time-input","path":"crates/labcolors-core/contracts/wcag22-srgb8-v1.json","sha256":"b4bb7e5f17a99f2c911fdbe3da23a48b049277b796291094950f14680cc3cc7b"},{"kind":"rust-source","path":"crates/labcolors-core/src/appearance.rs","sha256":"d31c6a7d3b0a4c02532759befaef442e3a99687263a9027771365638b6cc3324"},{"kind":"rust-source","path":"crates/labcolors-core/src/composition.rs","sha256":"195a67327a3bd86d7816b634481389930bf68577bb1202fad14c2ea152df8625"},{"kind":"rust-source","path":"crates/labcolors-core/src/constraints/exact.rs","sha256":"892576a8621185352583e63dc0a1aacac32e32a8063b6fe24ae16d4ff9dce7cb"},{"kind":"rust-source","path":"crates/labcolors-core/src/constraints/mod.rs","sha256":"aba84c05a203af12ef2e445334409d9bd385a854c9058f0e30bbf8542addddbc"},{"kind":"rust-source","path":"crates/labcolors-core/src/constraints/wcag22.rs","sha256":"856093c91159d8b3faab001f2d6524d33d7b16458a5a4e98ea65f8c62ab2694c"},{"kind":"rust-source","path":"crates/labcolors-core/src/hash.rs","sha256":"f97a0fd7d6ad3162f0f1dfb326fccfb7ed40da9a8fa67a5b8a239a1ae2ae49c3"},{"kind":"rust-source","path":"crates/labcolors-core/src/lcs_occurrence.rs","sha256":"78d37406e9bdc37f126b72987c9c92b452c13b3233c0aeb0a75ed25dadb83a68"},{"kind":"rust-source","path":"crates/labcolors-core/src/lib.rs","sha256":"b30300edd3910e3d9da1e56896ce14c3db508b1a6fc5608e01032a5ad95777b1"},{"kind":"rust-source","path":"crates/labcolors-core/src/numerics.rs","sha256":"e73a12136494f2ef9aca4e943ab38302c1439f054cecab36a552d35252c164f9"},{"kind":"rust-source","path":"crates/labcolors-core/src/observation.rs","sha256":"d31f5d5f95fbb2300c90899a26905c3cd2804be7c0e9290999005fd9e2c8f6d6"},{"kind":"rust-source","path":"crates/labcolors-core/src/point_support.rs","sha256":"6f6a376ff036d3d65960c004e6566e1bca580f19f5bd3cd333a80b0da5b5c242"},{"kind":"rust-source","path":"crates/labcolors-core/src/session.rs","sha256":"c7a1706ad4837adfdfbe58a302d20b613912530ebff260fd877a47210b02ef46"},{"kind":"rust-source","path":"crates/labcolors-core/src/srgb8.rs","sha256":"6c95324eb05476f35f75375a9af0b2b4a41b8b2978c46e67d2ce1aea5adde342"},{"kind":"rust-source","path":"crates/labcolors-core/src/wcag22.rs","sha256":"7ba7864eb7e73789bad6c63c64a4dc2dcc08c2da6921375fb9564fca230c2780"},{"kind":"rust-source","path":"crates/labcolors-core/src/wcag22/kernel.rs","sha256":"c97980c1ca2c7ea9cabff9c8d2fb7282773cca180ae15948391c29c9d6196040"},{"kind":"rust-source","path":"crates/labcolors-core/src/wcag22/q55_data.rs","sha256":"af4d23d6b70c45ce6efa839e7dda4bb0a61f6aae43cb805af6fa9b29e6c3bae2"},{"kind":"rust-source","path":"crates/labcolors-core/src/wcag22_evidence.rs","sha256":"3c5a75b07254c6071a64700af208a64987d0f0ea9698eadc54a9e74585ce1f72"}],"source_negative_controls":43,"universal_algebraic_certificate":{"basis_point_scale_instantiation":10000,"domain":"integers; Q55 scale Q>0; anchor L>=D>=0; lighter monotonicity L2>=L1>D>=0; darker monotonicity L>D2>=D1>=0; current/baseline denominators b,q>0; basis-point scale B>0 instantiated as 10000; p>0; a>=0; 0<=drop_bps<=B","identities":["three explicit anchor-surplus formulas after denominator clearing","reference distance is monotone increasing in lighter L","reference distance is monotone decreasing in darker D","positive-baseline retained threshold is p*(B-drop)/(q*B)","a/b >= p*(B-drop)/(q*B) iff a*q*B >= p*(B-drop)*b"],"method":"exact-sparse-integer-polynomial-identities-plus-positive-denominator-order-lemma-v1","nonpositive_baseline_case":"max(baseline,0)=0; retained threshold is exactly zero","symbolic_mutation_controls":{"anchor_coefficients_and_denominator":6,"retained_cross_product":5},"wolfram_language_cross_check":{"query":"FullSimplify[{20 g/d - 0 == 20 g/d, 20 g/d - 2 == (20 g - 2 d)/d, 20 g/d - 7/2 == (40 g - 7 d)/(2 d), Equivalent[a/b >= p (s-x)/(q s), a q s >= p (s-x) b], Max[p/q, 0] (s-x)/s == Piecewise[{{0, p <= 0}}, p (s-x)/(q s)]}, Assumptions -> Element[{a,b,p,q,s,x,g,d}, Integers] && a >= 0 && b > 0 && q > 0 && s > 0 && 0 <= x <= s && d > 0 && g >= 0]","query_sha256":"8cdbb9964583030c8b92498961896cb2a98613f1cb31eb7c54acdf8e16beff10","result":"{True, True, True, True, True}","result_sha256":"13a8f2ee8d0fde335a638e46d7cc8a8427b9a1437c77d22cfcf925bb87fa6303"}},"verifier_sha256":"5bb6f2b206d0504d3325ce2cd666a2efafe5f05a6db339549b87c8bf4199543d"} diff --git a/crates/labcolors-core/src/analog.rs b/crates/labcolors-core/src/analog.rs index 3365a9cf..5567ce31 100644 --- a/crates/labcolors-core/src/analog.rs +++ b/crates/labcolors-core/src/analog.rs @@ -452,7 +452,7 @@ mod tests { assert_eq!( evidence.physical, - PhysicalProgramIdentityV1::SolidOpacityOverSurfaceEncodedSrgb8V1 + PhysicalProgramIdentityV1::InputOpacityOverSurfaceEncodedSrgb8V1 ); assert_eq!( evidence.constraint, diff --git a/crates/labcolors-core/src/appearance.rs b/crates/labcolors-core/src/appearance.rs index 4602cb35..0f195ca7 100644 --- a/crates/labcolors-core/src/appearance.rs +++ b/crates/labcolors-core/src/appearance.rs @@ -31,11 +31,11 @@ use std::sync::Arc; use crate::Srgb8; pub(crate) use crate::composition::CompositionProfileV1; -/// Непрозрачный handle цветового входа. Число — только идентичность. +/// Непрозрачный handle атомарного Paint-входа. Число — только идентичность. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) struct ColorInputId(u32); +pub(crate) struct PaintInputId(u32); -impl ColorInputId { +impl PaintInputId { pub(crate) const fn new(raw: u32) -> Self { Self(raw) } @@ -43,7 +43,7 @@ impl ColorInputId { /// Непрозрачный handle наблюдаемого point-входа поверхности. /// -/// Он намеренно не взаимозаменяем с [`ColorInputId`]: authored Paint source и +/// Он намеренно не взаимозаменяем с [`PaintInputId`]: authored Paint и /// runtime backdrop имеют разные lifecycle и admission contract. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub(crate) struct SurfaceInputPortId(u32); @@ -122,7 +122,7 @@ impl OccurrenceId { /// topology/opcode/profile, а не числовые handles декларации или client ID. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum PhysicalProgramIdentityV1 { - SolidOpacityOverSurfaceEncodedSrgb8V1, + InputOpacityOverSurfaceEncodedSrgb8V1, } /// Routing внутри одной compiled point-программы отделён от физического @@ -151,10 +151,11 @@ impl ProgramOccurrenceBindingV1 { /// Paint-конструкторы point-домена. Ни один вариант не знает Surface. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum PaintSpec { - /// Непрозрачный encoded-sRGB8 Paint из цветового входа. - Solid { id: PaintId, color: ColorInputId }, + /// Атомарное encoded-sRGB8 + straight-alpha значение Paint-входа. + Input { id: PaintId, input: PaintInputId }, /// Модуляция straight alpha существующего Paint. /// + /// Связанный scalar является множителем, а не абсолютным новым alpha. /// Рёбра задают порядок операций: узел вычисляет одно binary64-произведение /// alpha источника и связанного scalar. Перегруппировка создаёт другую /// численную программу; алгебраическая ассоциативность f64 не заявляется. @@ -169,7 +170,7 @@ pub(crate) enum PaintSpec { impl PaintSpec { fn id(&self) -> PaintId { match self { - Self::Solid { id, .. } | Self::Opacity { id, .. } => *id, + Self::Input { id, .. } | Self::Opacity { id, .. } => *id, } } } @@ -208,8 +209,8 @@ pub(crate) struct OccurrenceSpec { /// Ошибки атомарной AOT-компиляции физической декларации. #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum CompileError { - DuplicateColorInput { - input: ColorInputId, + DuplicatePaintInput { + input: PaintInputId, }, DuplicateOpacityInput { input: OpacityInputId, @@ -226,9 +227,9 @@ pub(crate) enum CompileError { DuplicateOccurrence { occurrence: OccurrenceId, }, - MissingPaintColorInput { + MissingPaintInput { paint: PaintId, - input: ColorInputId, + input: PaintInputId, }, MissingPaintSource { paint: PaintId, @@ -269,8 +270,8 @@ pub(crate) enum CompileError { /// полной проверки, поэтому частичного результата нет. #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum BindingError { - DuplicateColorBinding { - input: ColorInputId, + DuplicatePaintInputBinding { + input: PaintInputId, }, DuplicateOpacityBinding { input: OpacityInputId, @@ -278,8 +279,8 @@ pub(crate) enum BindingError { DuplicateSurfaceInputBinding { input: SurfaceInputPortId, }, - MissingColorBinding { - input: ColorInputId, + MissingPaintInputBinding { + input: PaintInputId, }, MissingOpacityBinding { input: OpacityInputId, @@ -287,8 +288,8 @@ pub(crate) enum BindingError { MissingSurfaceInputBinding { input: SurfaceInputPortId, }, - UnexpectedColorBinding { - input: ColorInputId, + UnexpectedPaintInputBinding { + input: PaintInputId, }, UnexpectedOpacityBinding { input: OpacityInputId, @@ -327,7 +328,7 @@ impl PointOpacityError { /// Плоские декларации до атомарной компиляции. Порядок списков смысла не несёт. #[derive(Debug, Clone, PartialEq)] pub(crate) struct AppearanceGraphSpec { - color_inputs: Vec, + paint_inputs: Vec, surface_input_ports: Vec, opacity_inputs: Vec, paints: Vec, @@ -337,7 +338,7 @@ pub(crate) struct AppearanceGraphSpec { impl AppearanceGraphSpec { pub(crate) fn new( - color_inputs: Vec, + paint_inputs: Vec, surface_input_ports: Vec, opacity_inputs: Vec, paints: Vec, @@ -345,7 +346,7 @@ impl AppearanceGraphSpec { occurrences: Vec, ) -> Self { Self { - color_inputs, + paint_inputs, surface_input_ports, opacity_inputs, paints, @@ -358,7 +359,7 @@ impl AppearanceGraphSpec { /// детерминированных topo: Paint DAG и совместный Surface/Occurrence DAG. pub(crate) fn compile(self) -> Result { let Self { - mut color_inputs, + mut paint_inputs, mut surface_input_ports, mut opacity_inputs, mut paints, @@ -366,9 +367,9 @@ impl AppearanceGraphSpec { mut occurrences, } = self; - color_inputs.sort_unstable(); - if let Some(duplicate) = adjacent_duplicate(&color_inputs) { - return Err(CompileError::DuplicateColorInput { input: duplicate }); + paint_inputs.sort_unstable(); + if let Some(duplicate) = adjacent_duplicate(&paint_inputs) { + return Err(CompileError::DuplicatePaintInput { input: duplicate }); } surface_input_ports.sort_unstable(); @@ -411,7 +412,7 @@ impl AppearanceGraphSpec { }); } - let has_color = |id: ColorInputId| color_inputs.binary_search(&id).is_ok(); + let has_paint_input = |id: PaintInputId| paint_inputs.binary_search(&id).is_ok(); let has_surface_input = |id: SurfaceInputPortId| surface_input_ports.binary_search(&id).is_ok(); let has_opacity = |id: OpacityInputId| opacity_inputs.binary_search(&id).is_ok(); @@ -426,12 +427,9 @@ impl AppearanceGraphSpec { for paint in &paints { match *paint { - PaintSpec::Solid { id, color } => { - if !has_color(color) { - return Err(CompileError::MissingPaintColorInput { - paint: id, - input: color, - }); + PaintSpec::Input { id, input } => { + if !has_paint_input(input) { + return Err(CompileError::MissingPaintInput { paint: id, input }); } } PaintSpec::Opacity { @@ -491,7 +489,7 @@ impl AppearanceGraphSpec { let paint_dependencies: Vec> = paints .iter() .map(|paint| match *paint { - PaintSpec::Solid { .. } => None, + PaintSpec::Input { .. } => None, PaintSpec::Opacity { source, .. } => paint_index(source), }) .collect(); @@ -559,7 +557,7 @@ impl AppearanceGraphSpec { let compiled_paints = paints .iter() .map(|paint| match *paint { - PaintSpec::Solid { id, color } => CompiledPaintSpec::Solid { id, color }, + PaintSpec::Input { id, input } => CompiledPaintSpec::Input { id, input }, PaintSpec::Opacity { id, source, @@ -601,7 +599,7 @@ impl AppearanceGraphSpec { Ok(CompiledAppearanceGraph { instance: Arc::new(()), - color_inputs, + paint_inputs, surface_input_ports, opacity_inputs, paints: compiled_paints, @@ -719,9 +717,9 @@ enum RenderNode { #[derive(Debug, Clone, PartialEq, Eq)] enum CompiledPaintSpec { - Solid { + Input { id: PaintId, - color: ColorInputId, + input: PaintInputId, }, Opacity { id: PaintId, @@ -733,7 +731,7 @@ enum CompiledPaintSpec { impl CompiledPaintSpec { const fn id(&self) -> PaintId { match self { - Self::Solid { id, .. } | Self::Opacity { id, .. } => *id, + Self::Input { id, .. } | Self::Opacity { id, .. } => *id, } } } @@ -779,14 +777,14 @@ pub(crate) struct CompiledPaintSlotV1 { id: PaintId, } -/// Cold-bound canonical colour-input position used by finite Program targets. +/// Cold-bound canonical Paint-input position used by finite Program targets. /// The nominal ID is retained and rechecked on every overwrite. This rejects /// stale or mismatched index/ID pairs, but does not claim graph-instance /// identity when two graphs have the same canonical input at that position. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) struct CompiledColorInputSlotV1 { +pub(crate) struct CompiledPaintInputSlotV1 { index: usize, - id: ColorInputId, + id: PaintInputId, } /// Cold-bound canonical Occurrence position for allocation-free repeated @@ -877,7 +875,7 @@ pub(crate) enum PointOccurrenceAbsenceReplayErrorV1 { #[derive(Debug)] pub(crate) struct CompiledAppearanceGraph { instance: Arc<()>, - color_inputs: Vec, + paint_inputs: Vec, surface_input_ports: Vec, opacity_inputs: Vec, paints: Vec, @@ -892,19 +890,19 @@ pub(crate) struct CompiledAppearanceGraph { /// заранее доказанную топологию без повторной компиляции. #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct CompiledInputSchema<'a> { - color_inputs: &'a [ColorInputId], + paint_inputs: &'a [PaintInputId], surface_input_ports: &'a [SurfaceInputPortId], opacity_inputs: &'a [OpacityInputId], } impl<'a> CompiledInputSchema<'a> { const fn new( - color_inputs: &'a [ColorInputId], + paint_inputs: &'a [PaintInputId], surface_input_ports: &'a [SurfaceInputPortId], opacity_inputs: &'a [OpacityInputId], ) -> Self { Self { - color_inputs, + paint_inputs, surface_input_ports, opacity_inputs, } @@ -913,7 +911,7 @@ impl<'a> CompiledInputSchema<'a> { #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct CompiledAppearanceProgram<'a> { - color_inputs: &'a [ColorInputId], + paint_inputs: &'a [PaintInputId], surface_input_ports: &'a [SurfaceInputPortId], opacity_inputs: &'a [OpacityInputId], paints: &'a [CompiledPaintSpec], @@ -936,7 +934,7 @@ impl<'a> CompiledAppearanceProgram<'a> { render_topo: &'a [RenderNode], ) -> Self { Self { - color_inputs: inputs.color_inputs, + paint_inputs: inputs.paint_inputs, surface_input_ports: inputs.surface_input_ports, opacity_inputs: inputs.opacity_inputs, paints, @@ -948,7 +946,7 @@ impl<'a> CompiledAppearanceProgram<'a> { } } -const POINT_SOURCE: ColorInputId = ColorInputId::new(0); +const POINT_PAINT_INPUT: PaintInputId = PaintInputId::new(0); const POINT_CONTEXT: SurfaceInputPortId = SurfaceInputPortId::new(0); const POINT_OPACITY: OpacityInputId = OpacityInputId::new(0); const POINT_SOLID_PAINT: PaintId = PaintId::new(0); @@ -957,13 +955,13 @@ const POINT_CONTEXT_SURFACE: SurfaceId = SurfaceId::new(0); const POINT_DERIVED_SURFACE: SurfaceId = SurfaceId::new(1); const POINT_OCCURRENCE: OccurrenceId = OccurrenceId::new(0); -const POINT_COLOR_INPUTS: [ColorInputId; 1] = [POINT_SOURCE]; +const POINT_PAINT_INPUTS: [PaintInputId; 1] = [POINT_PAINT_INPUT]; const POINT_SURFACE_INPUT_PORTS: [SurfaceInputPortId; 1] = [POINT_CONTEXT]; const POINT_OPACITY_INPUTS: [OpacityInputId; 1] = [POINT_OPACITY]; const POINT_PAINTS: [CompiledPaintSpec; 2] = [ - CompiledPaintSpec::Solid { + CompiledPaintSpec::Input { id: POINT_SOLID_PAINT, - color: POINT_SOURCE, + input: POINT_PAINT_INPUT, }, CompiledPaintSpec::Opacity { id: POINT_OPACITY_PAINT, @@ -998,7 +996,7 @@ const POINT_RENDER_TOPO: [RenderNode; 3] = [ const POINT_OPACITY_OVER_SURFACE_V1: CompiledAppearanceProgram<'static> = CompiledAppearanceProgram::from_validated_parts( CompiledInputSchema::new( - &POINT_COLOR_INPUTS, + &POINT_PAINT_INPUTS, &POINT_SURFACE_INPUT_PORTS, &POINT_OPACITY_INPUTS, ), @@ -1015,7 +1013,7 @@ pub(crate) struct PointOpacityOverSurfaceV1; impl PointOpacityOverSurfaceV1 { pub(crate) const fn physical_identity() -> PhysicalProgramIdentityV1 { - PhysicalProgramIdentityV1::SolidOpacityOverSurfaceEncodedSrgb8V1 + PhysicalProgramIdentityV1::InputOpacityOverSurfaceEncodedSrgb8V1 } pub(crate) const fn composition_profile() -> CompositionProfileV1 { @@ -1054,8 +1052,8 @@ impl PointOpacityOverSurfaceV1 { let mut occurrences = [None; 1]; POINT_OPACITY_OVER_SURFACE_V1.execute_into( |id| { - debug_assert_eq!(id, POINT_SOURCE); - Srgb8::new(source) + debug_assert_eq!(id, POINT_PAINT_INPUT); + EncodedPointPaintValueV1::opaque(Srgb8::new(source)) }, |id| { debug_assert_eq!(id, POINT_CONTEXT); @@ -1076,13 +1074,13 @@ impl PointOpacityOverSurfaceV1 { #[cfg(test)] pub(crate) fn point_opacity_over_surface_declarative_spec() -> AppearanceGraphSpec { AppearanceGraphSpec::new( - POINT_COLOR_INPUTS.to_vec(), + POINT_PAINT_INPUTS.to_vec(), POINT_SURFACE_INPUT_PORTS.to_vec(), POINT_OPACITY_INPUTS.to_vec(), vec![ - PaintSpec::Solid { + PaintSpec::Input { id: POINT_SOLID_PAINT, - color: POINT_SOURCE, + input: POINT_PAINT_INPUT, }, PaintSpec::Opacity { id: POINT_OPACITY_PAINT, @@ -1117,22 +1115,22 @@ pub(crate) fn point_program_matches(compiled: &CompiledAppearanceGraph) -> bool /// Runtime bindings одного атомарного evaluate. #[derive(Debug, Clone, PartialEq)] pub(crate) struct AppearanceBindings { - colors: Vec<(ColorInputId, Srgb8)>, + paint_inputs: Vec<(PaintInputId, EncodedPointPaintValueV1)>, surfaces: Vec<(SurfaceInputPortId, Srgb8)>, opacities: Vec<(OpacityInputId, f64)>, } impl AppearanceBindings { pub(crate) fn new( - mut colors: Vec<(ColorInputId, Srgb8)>, + mut paint_inputs: Vec<(PaintInputId, EncodedPointPaintValueV1)>, mut surfaces: Vec<(SurfaceInputPortId, Srgb8)>, mut opacities: Vec<(OpacityInputId, f64)>, ) -> Self { - colors.sort_unstable_by_key(|(id, _)| *id); + paint_inputs.sort_unstable_by_key(|(id, _)| *id); surfaces.sort_unstable_by_key(|(id, _)| *id); opacities.sort_unstable_by_key(|(id, _)| *id); Self { - colors, + paint_inputs, surfaces, opacities, } @@ -1147,7 +1145,7 @@ impl AppearanceBindings { /// steady-state evaluate не повторяет numeric admission. #[derive(Debug, PartialEq, Eq)] pub(crate) struct AdmittedAppearanceBindings { - colors: Vec<(ColorInputId, Srgb8)>, + paint_inputs: Vec<(PaintInputId, EncodedPointPaintValueV1)>, surfaces: Vec<(SurfaceInputPortId, Srgb8)>, opacities: Vec<(OpacityInputId, crate::composition::AdmittedOpacityV1)>, } @@ -1169,7 +1167,7 @@ impl AdmittedAppearanceBindings { } Ok(Self { - colors: copy_vec(&self.colors)?, + paint_inputs: copy_vec(&self.paint_inputs)?, surfaces: copy_vec(&self.surfaces)?, opacities: copy_vec(&self.opacities)?, }) @@ -1202,12 +1200,12 @@ impl AdmittedAppearanceBindings { /// Overwrite one prebound finite-target input without lookup or allocation. /// The canonical index and nominal ID must both match before mutation. - pub(crate) fn overwrite_color_at( + pub(crate) fn overwrite_paint_input_at( &mut self, - slot: CompiledColorInputSlotV1, - value: Srgb8, + slot: CompiledPaintInputSlotV1, + value: EncodedPointPaintValueV1, ) -> Result<(), BindingError> { - let Some((bound, destination)) = self.colors.get_mut(slot.index) else { + let Some((bound, destination)) = self.paint_inputs.get_mut(slot.index) else { return Err(BindingError::IncompatibleAdmittedBindings); }; if *bound != slot.id { @@ -1233,13 +1231,13 @@ impl AdmittedAppearanceBindings { } fn matches_schema(&self, schema: CompiledInputSchema<'_>) -> bool { - schema.color_inputs.len() == self.colors.len() + schema.paint_inputs.len() == self.paint_inputs.len() && schema.surface_input_ports.len() == self.surfaces.len() && schema.opacity_inputs.len() == self.opacities.len() && schema - .color_inputs + .paint_inputs .iter() - .zip(&self.colors) + .zip(&self.paint_inputs) .all(|(declared, (bound, _))| declared == bound) && schema .surface_input_ports @@ -1254,33 +1252,26 @@ impl AdmittedAppearanceBindings { } } -/// Материализованный encoded point Paint вне зависимости от стадии владения. +/// ID-free атомарное значение encoded point Paint. /// -/// Graph materialization и downstream recheck разделяют это одно физическое -/// значение. Тип alpha делает повторную admission перед каждым occurrence -/// невозможной; его биты без потерь переходят в certificate. +/// Источник и straight alpha изменяются только вместе: это не позволяет solver-у +/// создать не объявленную клиентом декартову комбинацию двух независимых осей. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) struct EncodedPointPaintV1 { - id: PaintId, +pub(crate) struct EncodedPointPaintValueV1 { source: Srgb8, opacity: crate::composition::AdmittedOpacityV1, } -impl EncodedPointPaintV1 { +impl EncodedPointPaintValueV1 { pub(crate) const fn from_admitted( - id: PaintId, source: Srgb8, opacity: crate::composition::AdmittedOpacityV1, ) -> Self { - Self { - id, - source, - opacity, - } + Self { source, opacity } } - pub(crate) const fn id(self) -> PaintId { - self.id + pub(crate) const fn opaque(source: Srgb8) -> Self { + Self::from_admitted(source, crate::composition::AdmittedOpacityV1::OPAQUE) } pub(crate) const fn source(self) -> Srgb8 { @@ -1296,6 +1287,43 @@ impl EncodedPointPaintV1 { } } +/// Материализованный encoded point Paint вне зависимости от стадии владения. +/// +/// Graph materialization и downstream recheck разделяют это одно физическое +/// значение. Тип alpha делает повторную admission перед каждым occurrence +/// невозможной; его биты без потерь переходят в certificate. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct EncodedPointPaintV1 { + id: PaintId, + value: EncodedPointPaintValueV1, +} + +impl EncodedPointPaintV1 { + pub(crate) const fn from_value(id: PaintId, value: EncodedPointPaintValueV1) -> Self { + Self { id, value } + } + + pub(crate) const fn id(self) -> PaintId { + self.id + } + + pub(crate) const fn source(self) -> Srgb8 { + self.value.source() + } + + pub(crate) const fn opacity(self) -> crate::composition::AdmittedOpacityV1 { + self.value.opacity() + } + + pub(crate) const fn opacity_bits(self) -> u64 { + self.value.opacity_bits() + } + + pub(crate) const fn value(self) -> EncodedPointPaintValueV1 { + self.value + } +} + /// Replayable exact point-composite certificate. Он доказывает только /// заявленную математическую операцию, не readability и не browser pixels. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -1890,7 +1918,7 @@ impl CompiledAppearanceGraph { fn program(&self) -> CompiledAppearanceProgram<'_> { CompiledAppearanceProgram::from_validated_parts( CompiledInputSchema::new( - &self.color_inputs, + &self.paint_inputs, &self.surface_input_ports, &self.opacity_inputs, ), @@ -1907,11 +1935,11 @@ impl CompiledAppearanceGraph { self.program() == program } - /// Bind one colour input to its canonical compiled ordinal. Runtime target + /// Bind one Paint input to its canonical compiled ordinal. Runtime target /// selection consumes the sealed slot instead of repeating an ID search. - pub(crate) fn bind_color_input(&self, id: ColorInputId) -> Option { - let index = self.color_inputs.binary_search(&id).ok()?; - Some(CompiledColorInputSlotV1 { index, id }) + pub(crate) fn bind_paint_input(&self, id: PaintInputId) -> Option { + let index = self.paint_inputs.binary_search(&id).ok()?; + Some(CompiledPaintInputSlotV1 { index, id }) } /// Bind one Paint identity to its canonical compiled ordinal. @@ -2085,7 +2113,7 @@ impl CompiledAppearanceGraph { impl<'program> CompiledAppearanceProgram<'program> { const fn input_schema(self) -> CompiledInputSchema<'program> { CompiledInputSchema::new( - self.color_inputs, + self.paint_inputs, self.surface_input_ports, self.opacity_inputs, ) @@ -2095,9 +2123,12 @@ impl<'program> CompiledAppearanceProgram<'program> { &self, bindings: &AppearanceBindings, ) -> Result { - let colors = &bindings.colors; - if let Some(window) = colors.windows(2).find(|window| window[0].0 == window[1].0) { - return Err(BindingError::DuplicateColorBinding { input: window[0].0 }); + let paint_inputs = &bindings.paint_inputs; + if let Some(window) = paint_inputs + .windows(2) + .find(|window| window[0].0 == window[1].0) + { + return Err(BindingError::DuplicatePaintInputBinding { input: window[0].0 }); } let opacities = &bindings.opacities; if let Some(window) = opacities @@ -2114,12 +2145,12 @@ impl<'program> CompiledAppearanceProgram<'program> { return Err(BindingError::DuplicateSurfaceInputBinding { input: window[0].0 }); } - for declared in self.color_inputs { - if colors + for declared in self.paint_inputs { + if paint_inputs .binary_search_by_key(declared, |(id, _)| *id) .is_err() { - return Err(BindingError::MissingColorBinding { input: *declared }); + return Err(BindingError::MissingPaintInputBinding { input: *declared }); } } for declared in self.opacity_inputs { @@ -2138,9 +2169,9 @@ impl<'program> CompiledAppearanceProgram<'program> { return Err(BindingError::MissingSurfaceInputBinding { input: *declared }); } } - for (bound, _) in colors { - if self.color_inputs.binary_search(bound).is_err() { - return Err(BindingError::UnexpectedColorBinding { input: *bound }); + for (bound, _) in paint_inputs { + if self.paint_inputs.binary_search(bound).is_err() { + return Err(BindingError::UnexpectedPaintInputBinding { input: *bound }); } } for (bound, _) in opacities { @@ -2154,11 +2185,11 @@ impl<'program> CompiledAppearanceProgram<'program> { } } - let mut admitted_colors = Vec::new(); - admitted_colors - .try_reserve_exact(colors.len()) + let mut admitted_paint_inputs = Vec::new(); + admitted_paint_inputs + .try_reserve_exact(paint_inputs.len()) .map_err(|_| BindingError::ResourceExhausted)?; - admitted_colors.extend(colors.iter().copied()); + admitted_paint_inputs.extend(paint_inputs.iter().copied()); let mut admitted_surfaces = Vec::new(); admitted_surfaces @@ -2181,7 +2212,7 @@ impl<'program> CompiledAppearanceProgram<'program> { } Ok(AdmittedAppearanceBindings { - colors: admitted_colors, + paint_inputs: admitted_paint_inputs, surfaces: admitted_surfaces, opacities: admitted_opacities, }) @@ -2198,15 +2229,15 @@ impl<'program> CompiledAppearanceProgram<'program> { } workspace.prepare(self)?; - let colors = &bindings.colors; + let paint_inputs = &bindings.paint_inputs; let surfaces = &bindings.surfaces; let opacities = &bindings.opacities; - let color_value = |id: ColorInputId| -> Srgb8 { - let index = colors + let paint_input_value = |id: PaintInputId| -> EncodedPointPaintValueV1 { + let index = paint_inputs .binary_search_by_key(&id, |(bound, _)| *bound) .unwrap_or_else(|_| unreachable!("bindings were matched before evaluation")); - colors[index].1 + paint_inputs[index].1 }; let surface_value = |id: SurfaceInputPortId| -> Srgb8 { let index = surfaces @@ -2222,7 +2253,7 @@ impl<'program> CompiledAppearanceProgram<'program> { }; self.execute_into( - color_value, + paint_input_value, surface_value, opacity_value, &mut workspace.paints, @@ -2240,16 +2271,16 @@ impl<'program> CompiledAppearanceProgram<'program> { /// Единственное исполнение compiled IR. Scratch принадлежит caller-у: /// static adapter использует stack arrays, generic admission — /// владеющие buffers. Алгоритм и сертификат при этом общие. - fn execute_into( + fn execute_into( &self, - color_value: C, + paint_input_value: P, surface_value: S, opacity_value: O, resolved_paints: &mut [Option], resolved_surfaces: &mut [Option], resolved_occurrences: &mut [Option], ) where - C: Fn(ColorInputId) -> Srgb8, + P: Fn(PaintInputId) -> EncodedPointPaintValueV1, S: Fn(SurfaceInputPortId) -> Srgb8, O: Fn(OpacityInputId) -> crate::composition::AdmittedOpacityV1, { @@ -2259,11 +2290,9 @@ impl<'program> CompiledAppearanceProgram<'program> { for &index in self.paint_topo { let paint = match self.paints[index] { - CompiledPaintSpec::Solid { id, color } => EncodedPointPaintV1::from_admitted( - id, - color_value(color), - crate::composition::AdmittedOpacityV1::OPAQUE, - ), + CompiledPaintSpec::Input { id, input } => { + EncodedPointPaintV1::from_value(id, paint_input_value(input)) + } CompiledPaintSpec::Opacity { id, source, @@ -2272,10 +2301,13 @@ impl<'program> CompiledAppearanceProgram<'program> { // Валидированный `paint_topo` всегда материализует source // раньше зависимого Opacity-узла. let source = resolved_paints[source].unwrap_or_else(|| unreachable!()); - EncodedPointPaintV1::from_admitted( + let value = source.value(); + EncodedPointPaintV1::from_value( id, - source.source, - source.opacity.multiply(opacity_value(opacity)), + EncodedPointPaintValueV1::from_admitted( + value.source(), + value.opacity().multiply(opacity_value(opacity)), + ), ) } }; @@ -2302,8 +2334,8 @@ impl<'program> CompiledAppearanceProgram<'program> { resolved_surfaces[spec.against].unwrap_or_else(|| unreachable!()); let certificate = SourceOverCertificateV1::compose( spec.profile, - subject.source.bytes(), - subject.opacity, + subject.source().bytes(), + subject.opacity(), backdrop.bytes(), ); let visible = certificate.output_rgb(); diff --git a/crates/labcolors-core/src/appearance_graph_tests.rs b/crates/labcolors-core/src/appearance_graph_tests.rs index afb9af03..5f79920b 100644 --- a/crates/labcolors-core/src/appearance_graph_tests.rs +++ b/crates/labcolors-core/src/appearance_graph_tests.rs @@ -12,14 +12,14 @@ use proptest::prelude::*; use crate::Srgb8; use crate::appearance::{ AdmittedAppearanceBindings, AppearanceBindings, AppearanceGraphSpec, BindingError, - ColorInputId, CompileError, CompositionProfileV1, EncodedPointPaintV1, OccurrenceId, - OccurrenceSpec, OpacityInputId, PaintId, PaintSpec, PointPresentationPathErrorV1, SurfaceId, - SurfaceInputPortId, SurfaceSpec, + CompileError, CompositionProfileV1, EncodedPointPaintV1, EncodedPointPaintValueV1, + OccurrenceId, OccurrenceSpec, OpacityInputId, PaintId, PaintInputId, PaintSpec, + PointPresentationPathErrorV1, SurfaceId, SurfaceInputPortId, SurfaceSpec, }; use crate::constraints::Evaluator; -const SOURCE: ColorInputId = ColorInputId::new(0); -const OTHER_SOURCE: ColorInputId = ColorInputId::new(2); +const SOURCE: PaintInputId = PaintInputId::new(0); +const OTHER_SOURCE: PaintInputId = PaintInputId::new(2); const CONTEXT: SurfaceInputPortId = SurfaceInputPortId::new(1); const OTHER_CONTEXT: SurfaceInputPortId = SurfaceInputPortId::new(2); const OPACITY: OpacityInputId = OpacityInputId::new(0); @@ -32,11 +32,15 @@ const DERIVED_SURFACE: SurfaceId = SurfaceId::new(2); const FILL_OCCURRENCE: OccurrenceId = OccurrenceId::new(800); const OTHER_OCCURRENCE: OccurrenceId = OccurrenceId::new(400); +fn opaque(source: [u8; 3]) -> EncodedPointPaintValueV1 { + EncodedPointPaintValueV1::opaque(Srgb8::new(source)) +} + fn point_component(reverse_paints: bool, reverse_surfaces: bool) -> AppearanceGraphSpec { let mut paints = vec![ - PaintSpec::Solid { + PaintSpec::Input { id: SOLID_PAINT, - color: SOURCE, + input: SOURCE, }, PaintSpec::Opacity { id: FILL_PAINT, @@ -78,7 +82,7 @@ fn point_component(reverse_paints: bool, reverse_surfaces: bool) -> AppearanceGr fn bindings(source: [u8; 3], opacity: f64, context: [u8; 3]) -> AppearanceBindings { AppearanceBindings::new( - vec![(SOURCE, Srgb8::new(source))], + vec![(SOURCE, opaque(source))], vec![(CONTEXT, Srgb8::new(context))], vec![(OPACITY, opacity)], ) @@ -89,9 +93,9 @@ fn terminal_chain() -> AppearanceGraphSpec { vec![SOURCE], vec![CONTEXT], vec![], - vec![PaintSpec::Solid { + vec![PaintSpec::Input { id: SOLID_PAINT, - color: SOURCE, + input: SOURCE, }], vec![ SurfaceSpec::Input { @@ -191,13 +195,13 @@ fn compiled_appearance_graph_remains_send_and_sync() { fn slot_component(reverse_declarations: bool) -> AppearanceGraphSpec { let mut paints = vec![ - PaintSpec::Solid { + PaintSpec::Input { id: SOLID_PAINT, - color: SOURCE, + input: SOURCE, }, - PaintSpec::Solid { + PaintSpec::Input { id: FILL_PAINT, - color: OTHER_SOURCE, + input: OTHER_SOURCE, }, ]; let mut occurrences = vec![ @@ -262,7 +266,7 @@ fn static_exact_program_is_declarative_topology_plus_typed_constraint() { assert!(crate::appearance::point_program_matches(&compiled)); assert_eq!( crate::analog::ExactAlphaProgramV1::physical_identity(), - crate::appearance::PhysicalProgramIdentityV1::SolidOpacityOverSurfaceEncodedSrgb8V1 + crate::appearance::PhysicalProgramIdentityV1::InputOpacityOverSurfaceEncodedSrgb8V1 ); assert_eq!( (), context in any::<[u8; 3]>(), - alphas in proptest::collection::vec(0.0f64..=1.0f64, 0..=8), + base_alpha in f64::MIN_POSITIVE..1.0f64, + alphas in proptest::collection::vec(0.0f64..=1.0f64, 1..=8), ) { let opacity_inputs: Vec = (0..alphas.len()) .map(|index| OpacityInputId::new(index as u32)) .collect(); - let mut paints = vec![PaintSpec::Solid { + let mut paints = vec![PaintSpec::Input { id: SOLID_PAINT, - color: SOURCE, + input: SOURCE, }]; let mut subject = SOLID_PAINT; for (index, opacity) in opacity_inputs.iter().copied().enumerate() { @@ -1188,10 +1255,17 @@ proptest! { ) .compile() .unwrap(); - let effective = alphas.iter().copied().fold(1.0, |product, alpha| product * alpha); + let effective = alphas + .iter() + .copied() + .fold(base_alpha, |product, alpha| product * alpha); + let base = EncodedPointPaintValueV1::from_admitted( + Srgb8::new(source), + crate::composition::AdmittedOpacityV1::new(base_alpha).unwrap(), + ); let rendered = graph .evaluate(&AppearanceBindings::new( - vec![(SOURCE, Srgb8::new(source))], + vec![(SOURCE, base)], vec![(CONTEXT, Srgb8::new(context))], opacity_inputs .iter() @@ -1224,9 +1298,9 @@ proptest! { vec![CONTEXT], vec![OPACITY, OTHER_OPACITY], vec![ - PaintSpec::Solid { + PaintSpec::Input { id: SOLID_PAINT, - color: SOURCE, + input: SOURCE, }, PaintSpec::Opacity { id: FILL_PAINT, @@ -1261,7 +1335,7 @@ proptest! { crate::composition::AdmittedOpacityV1::new(invalid).unwrap_err(); prop_assert_eq!( graph.evaluate(&AppearanceBindings::new( - vec![(SOURCE, Srgb8::new([1, 2, 3]))], + vec![(SOURCE, opaque([1, 2, 3]))], vec![(CONTEXT, Srgb8::new([4, 5, 6]))], vec![(OPACITY, inner), (OTHER_OPACITY, outer)], )), @@ -1288,10 +1362,12 @@ proptest! { Err(crate::composition::OpacityAdmissionErrorV1::OutsideUnitInterval) ); } else { - let paint = EncodedPointPaintV1::from_admitted( + let paint = EncodedPointPaintV1::from_value( FILL_PAINT, - Srgb8::new([1, 2, 3]), - admission.unwrap(), + EncodedPointPaintValueV1::from_admitted( + Srgb8::new([1, 2, 3]), + admission.unwrap(), + ), ); let expected_bits = if alpha == 0.0 { 0.0f64.to_bits() @@ -1311,7 +1387,7 @@ fn compile_rejects_duplicate_declarations_with_typed_errors() { AppearanceGraphSpec::new(vec![SOURCE, SOURCE], vec![], vec![], vec![], vec![], vec![]) .compile() .unwrap_err(), - CompileError::DuplicateColorInput { input: SOURCE } + CompileError::DuplicatePaintInput { input: SOURCE } ); assert_eq!( AppearanceGraphSpec::new( @@ -1345,13 +1421,13 @@ fn compile_rejects_duplicate_declarations_with_typed_errors() { vec![], vec![], vec![ - PaintSpec::Solid { + PaintSpec::Input { id: SOLID_PAINT, - color: SOURCE, + input: SOURCE, }, - PaintSpec::Solid { + PaintSpec::Input { id: SOLID_PAINT, - color: OTHER_SOURCE, + input: OTHER_SOURCE, }, ], vec![], @@ -1421,9 +1497,9 @@ fn compile_rejects_every_dangling_canonical_edge() { vec![], vec![], vec![], - vec![PaintSpec::Solid { + vec![PaintSpec::Input { id: SOLID_PAINT, - color: SOURCE, + input: SOURCE, }], vec![], vec![], @@ -1431,7 +1507,7 @@ fn compile_rejects_every_dangling_canonical_edge() { .compile(); assert_eq!( missing_color.unwrap_err(), - CompileError::MissingPaintColorInput { + CompileError::MissingPaintInput { paint: SOLID_PAINT, input: SOURCE, } @@ -1463,9 +1539,9 @@ fn compile_rejects_every_dangling_canonical_edge() { vec![], vec![], vec![ - PaintSpec::Solid { + PaintSpec::Input { id: SOLID_PAINT, - color: SOURCE, + input: SOURCE, }, PaintSpec::Opacity { id: FILL_PAINT, @@ -1554,9 +1630,9 @@ fn compile_rejects_every_dangling_canonical_edge() { vec![SOURCE], vec![], vec![], - vec![PaintSpec::Solid { + vec![PaintSpec::Input { id: SOLID_PAINT, - color: SOURCE, + input: SOURCE, }], vec![], vec![OccurrenceSpec { @@ -1621,9 +1697,9 @@ fn cycle_errors_contain_only_actual_cycle_members() { vec![SOURCE], vec![], vec![], - vec![PaintSpec::Solid { + vec![PaintSpec::Input { id: SOLID_PAINT, - color: SOURCE, + input: SOURCE, }], vec![ SurfaceSpec::FromOccurrence { @@ -1665,18 +1741,15 @@ fn evaluate_rejects_duplicate_missing_and_unexpected_bindings() { let graph = point_component(false, false).compile().unwrap(); assert_eq!( graph.evaluate(&AppearanceBindings::new( - vec![ - (SOURCE, Srgb8::new([1, 2, 3])), - (SOURCE, Srgb8::new([7, 8, 9])), - ], + vec![(SOURCE, opaque([1, 2, 3])), (SOURCE, opaque([7, 8, 9])),], vec![(CONTEXT, Srgb8::new([4, 5, 6]))], vec![(OPACITY, 0.5)], )), - Err(BindingError::DuplicateColorBinding { input: SOURCE }) + Err(BindingError::DuplicatePaintInputBinding { input: SOURCE }) ); assert_eq!( graph.evaluate(&AppearanceBindings::new( - vec![(SOURCE, Srgb8::new([1, 2, 3]))], + vec![(SOURCE, opaque([1, 2, 3]))], vec![(CONTEXT, Srgb8::new([4, 5, 6]))], vec![(OPACITY, 0.5), (OPACITY, 0.6)], )), @@ -1688,11 +1761,11 @@ fn evaluate_rejects_duplicate_missing_and_unexpected_bindings() { vec![(CONTEXT, Srgb8::new([4, 5, 6]))], vec![(OPACITY, 0.5)], )), - Err(BindingError::MissingColorBinding { input: SOURCE }) + Err(BindingError::MissingPaintInputBinding { input: SOURCE }) ); assert_eq!( graph.evaluate(&AppearanceBindings::new( - vec![(SOURCE, Srgb8::new([1, 2, 3]))], + vec![(SOURCE, opaque([1, 2, 3]))], vec![], vec![(OPACITY, 0.5)], )), @@ -1700,7 +1773,7 @@ fn evaluate_rejects_duplicate_missing_and_unexpected_bindings() { ); assert_eq!( graph.evaluate(&AppearanceBindings::new( - vec![(SOURCE, Srgb8::new([1, 2, 3]))], + vec![(SOURCE, opaque([1, 2, 3]))], vec![(CONTEXT, Srgb8::new([4, 5, 6]))], vec![], )), @@ -1709,19 +1782,19 @@ fn evaluate_rejects_duplicate_missing_and_unexpected_bindings() { assert_eq!( graph.evaluate(&AppearanceBindings::new( vec![ - (SOURCE, Srgb8::new([1, 2, 3])), - (ColorInputId::new(9), Srgb8::new([7, 8, 9])), + (SOURCE, opaque([1, 2, 3])), + (PaintInputId::new(9), opaque([7, 8, 9])), ], vec![(CONTEXT, Srgb8::new([4, 5, 6]))], vec![(OPACITY, 0.5)], )), - Err(BindingError::UnexpectedColorBinding { - input: ColorInputId::new(9), + Err(BindingError::UnexpectedPaintInputBinding { + input: PaintInputId::new(9), }) ); assert_eq!( graph.evaluate(&AppearanceBindings::new( - vec![(SOURCE, Srgb8::new([1, 2, 3]))], + vec![(SOURCE, opaque([1, 2, 3]))], vec![(CONTEXT, Srgb8::new([4, 5, 6]))], vec![(OPACITY, 0.5), (OpacityInputId::new(9), 0.5)], )), @@ -1731,7 +1804,7 @@ fn evaluate_rejects_duplicate_missing_and_unexpected_bindings() { ); assert_eq!( graph.evaluate(&AppearanceBindings::new( - vec![(SOURCE, Srgb8::new([1, 2, 3]))], + vec![(SOURCE, opaque([1, 2, 3]))], vec![ (CONTEXT, Srgb8::new([4, 5, 6])), (SurfaceInputPortId::new(9), Srgb8::new([7, 8, 9])), @@ -1750,7 +1823,7 @@ fn binding_admission_is_atomic_before_any_occurrence_is_evaluated() { crate::composition::reset_source_over_evaluation_count(); let duplicate_surface = graph.evaluate(&AppearanceBindings::new( - vec![(SOURCE, Srgb8::new([1, 2, 3]))], + vec![(SOURCE, opaque([1, 2, 3]))], vec![ (CONTEXT, Srgb8::new([4, 5, 6])), (CONTEXT, Srgb8::new([7, 8, 9])), @@ -1986,7 +2059,7 @@ fn admitted_schema_and_workspace_shape_mismatches_fail_before_composition() { assert_eq!(crate::composition::source_over_evaluation_count(), 0); assert_eq!(wrong_workspace.storage_signature(), wrong_storage); - let other_source = ColorInputId::new(100); + let other_source = PaintInputId::new(100); let other_context = SurfaceInputPortId::new(101); let other_opacity = OpacityInputId::new(102); let other_solid = PaintId::new(103); @@ -1999,9 +2072,9 @@ fn admitted_schema_and_workspace_shape_mismatches_fail_before_composition() { vec![other_context], vec![other_opacity], vec![ - PaintSpec::Solid { + PaintSpec::Input { id: other_solid, - color: other_source, + input: other_source, }, PaintSpec::Opacity { id: other_paint, @@ -2030,7 +2103,7 @@ fn admitted_schema_and_workspace_shape_mismatches_fail_before_composition() { .unwrap(); let other_admitted = other .admit_bindings(&AppearanceBindings::new( - vec![(other_source, Srgb8::new([1, 2, 3]))], + vec![(other_source, opaque([1, 2, 3]))], vec![(other_context, Srgb8::new([4, 5, 6]))], vec![(other_opacity, 0.5)], )) diff --git a/crates/labcolors-core/src/appearance_replay_tests.rs b/crates/labcolors-core/src/appearance_replay_tests.rs index 688a6d98..3ee7aaee 100644 --- a/crates/labcolors-core/src/appearance_replay_tests.rs +++ b/crates/labcolors-core/src/appearance_replay_tests.rs @@ -8,9 +8,9 @@ use proptest::prelude::*; use crate::Srgb8; use crate::appearance::{ - AppearanceBindings, AppearanceGraphSpec, ColorInputId, CompositionProfileV1, - ExactFinalOwnedPointDomainV1, OccurrenceId, OccurrenceSpec, OpacityInputId, PaintId, PaintSpec, - PointOccurrenceAbsenceReleaseV1, PointOccurrenceAbsenceReplayErrorV1, + AppearanceBindings, AppearanceGraphSpec, CompositionProfileV1, EncodedPointPaintValueV1, + ExactFinalOwnedPointDomainV1, OccurrenceId, OccurrenceSpec, OpacityInputId, PaintId, + PaintInputId, PaintSpec, PointOccurrenceAbsenceReleaseV1, PointOccurrenceAbsenceReplayErrorV1, PointOccurrenceAbsenceStepV1, SurfaceId, SurfaceInputPortId, SurfaceSpec, }; @@ -25,8 +25,8 @@ struct ReplaySummary { steps: Vec, } -fn color(index: usize) -> ColorInputId { - ColorInputId::new(u32::try_from(10 + index).unwrap()) +fn paint_input(index: usize) -> PaintInputId { + PaintInputId::new(u32::try_from(10 + index).unwrap()) } fn opacity(index: usize) -> OpacityInputId { @@ -59,7 +59,7 @@ fn chain( assert!(!layers.is_empty()); let input = SurfaceInputPortId::new(300); let input_surface = SurfaceId::new(301); - let mut colors = Vec::new(); + let mut paint_inputs = Vec::new(); let mut opacities = Vec::new(); let mut paints = Vec::new(); let mut surfaces = vec![SurfaceSpec::Input { @@ -67,15 +67,15 @@ fn chain( port: input, }]; let mut occurrences = Vec::new(); - let mut color_bindings = Vec::new(); + let mut paint_input_bindings = Vec::new(); let mut opacity_bindings = Vec::new(); for (index, &(source, alpha)) in layers.iter().enumerate() { - colors.push(color(index)); + paint_inputs.push(paint_input(index)); opacities.push(opacity(index)); - paints.push(PaintSpec::Solid { + paints.push(PaintSpec::Input { id: solid(index), - color: color(index), + input: paint_input(index), }); paints.push(PaintSpec::Opacity { id: translucent(index), @@ -96,7 +96,10 @@ fn chain( id: derived_surface(index), occurrence: occurrence(index), }); - color_bindings.push((color(index), Srgb8::new(source))); + paint_input_bindings.push(( + paint_input(index), + EncodedPointPaintValueV1::opaque(Srgb8::new(source)), + )); opacity_bindings.push((opacity(index), alpha)); } @@ -106,7 +109,7 @@ fn chain( surfaces.reverse(); occurrences.reverse(); let graph = AppearanceGraphSpec::new( - colors, + paint_inputs, vec![input], opacities, paints, @@ -116,7 +119,7 @@ fn chain( .compile() .unwrap(); let bindings = AppearanceBindings::new( - color_bindings, + paint_input_bindings, vec![(input, Srgb8::new(backdrop))], opacity_bindings, ); @@ -355,9 +358,9 @@ fn final_domain_is_scoped_to_one_selected_root_in_a_fanout_graph() { let shared_surface = derived_surface(0); let mut paints = Vec::new(); for index in 0..3 { - paints.push(PaintSpec::Solid { + paints.push(PaintSpec::Input { id: solid(index), - color: color(index), + input: paint_input(index), }); paints.push(PaintSpec::Opacity { id: translucent(index), @@ -367,7 +370,7 @@ fn final_domain_is_scoped_to_one_selected_root_in_a_fanout_graph() { } paints.reverse(); let graph = AppearanceGraphSpec::new( - (0..3).map(color).collect(), + (0..3).map(paint_input).collect(), vec![input], (0..3).map(opacity).collect(), paints, @@ -406,9 +409,18 @@ fn final_domain_is_scoped_to_one_selected_root_in_a_fanout_graph() { .unwrap(); let bindings = AppearanceBindings::new( vec![ - (color(0), Srgb8::new([240, 30, 10])), - (color(1), Srgb8::new([5, 200, 90])), - (color(2), Srgb8::new([220, 180, 70])), + ( + paint_input(0), + EncodedPointPaintValueV1::opaque(Srgb8::new([240, 30, 10])), + ), + ( + paint_input(1), + EncodedPointPaintValueV1::opaque(Srgb8::new([5, 200, 90])), + ), + ( + paint_input(2), + EncodedPointPaintValueV1::opaque(Srgb8::new([220, 180, 70])), + ), ], vec![(input, Srgb8::new([31, 47, 89]))], vec![(opacity(0), 0.5), (opacity(1), 1.0), (opacity(2), 0.25)], diff --git a/crates/labcolors-core/src/constraint_tests.rs b/crates/labcolors-core/src/constraint_tests.rs index 9127f5e1..caaa3474 100644 --- a/crates/labcolors-core/src/constraint_tests.rs +++ b/crates/labcolors-core/src/constraint_tests.rs @@ -2,9 +2,9 @@ use proptest::prelude::*; use crate::Srgb8; use crate::appearance::{ - AppearanceBindings, AppearanceGraphSpec, ColorInputId, CompositionProfileV1, OccurrenceId, - OccurrenceSpec, OpacityInputId, PaintId, PaintSpec, PointOpacityOverSurfaceV1, SurfaceId, - SurfaceInputPortId, SurfaceSpec, VisiblePointBindingV1, + AppearanceBindings, AppearanceGraphSpec, CompositionProfileV1, EncodedPointPaintValueV1, + OccurrenceId, OccurrenceSpec, OpacityInputId, PaintId, PaintInputId, PaintSpec, + PointOpacityOverSurfaceV1, SurfaceId, SurfaceInputPortId, SurfaceSpec, VisiblePointBindingV1, }; use crate::constraints::{ ApplicableWcag22EvaluationErrorV1, ApplicableWcag22MeasurementV1, ClassifiedMeasurement, @@ -262,7 +262,7 @@ fn modeled_target_has_no_binding_or_source_capability() { } fn two_equal_physical_occurrences() -> [crate::appearance::ResolvedOccurrence; 2] { - let source = ColorInputId::new(0); + let source = PaintInputId::new(0); let backdrop = SurfaceInputPortId::new(1); let opacity = OpacityInputId::new(0); let solid = PaintId::new(0); @@ -277,9 +277,9 @@ fn two_equal_physical_occurrences() -> [crate::appearance::ResolvedOccurrence; 2 vec![backdrop], vec![opacity], vec![ - PaintSpec::Solid { + PaintSpec::Input { id: solid, - color: source, + input: source, }, PaintSpec::Opacity { id: translucent, @@ -320,7 +320,10 @@ fn two_equal_physical_occurrences() -> [crate::appearance::ResolvedOccurrence; 2 .expect("acyclic typed graph must compile"); let evaluation = graph .evaluate(&AppearanceBindings::new( - vec![(source, crate::Srgb8::new([0, 64, 255]))], + vec![( + source, + EncodedPointPaintValueV1::opaque(crate::Srgb8::new([0, 64, 255])), + )], vec![(backdrop, crate::Srgb8::new([255, 255, 255]))], vec![(opacity, 0.5)], )) diff --git a/crates/labcolors-core/src/joint_tests.rs b/crates/labcolors-core/src/joint_tests.rs index bd6d556d..52cbd969 100644 --- a/crates/labcolors-core/src/joint_tests.rs +++ b/crates/labcolors-core/src/joint_tests.rs @@ -1,5 +1,7 @@ use crate::Srgb8; -use crate::appearance::{EncodedPointPaintV1, PaintId, SurfaceInputPortId}; +use crate::appearance::{ + EncodedPointPaintV1, EncodedPointPaintValueV1, PaintId, SurfaceInputPortId, +}; use crate::composition::AdmittedOpacityV1; use crate::constraints::{ExactSrgb8IdentityV1, HardDecision, Wcag22Srgb8V1}; use crate::joint::{ @@ -40,10 +42,12 @@ impl ObservationOwnerV1 for EmptyObservationOwner { } fn paint(id: PaintId, bytes: [u8; 3], opacity: f64) -> EncodedPointPaintV1 { - EncodedPointPaintV1::from_admitted( + EncodedPointPaintV1::from_value( id, - Srgb8::new(bytes), - AdmittedOpacityV1::new(opacity).unwrap(), + EncodedPointPaintValueV1::from_admitted( + Srgb8::new(bytes), + AdmittedOpacityV1::new(opacity).unwrap(), + ), ) } diff --git a/crates/labcolors-core/src/observation_tests.rs b/crates/labcolors-core/src/observation_tests.rs index d5b30365..ef52a619 100644 --- a/crates/labcolors-core/src/observation_tests.rs +++ b/crates/labcolors-core/src/observation_tests.rs @@ -6,9 +6,10 @@ use proptest::test_runner::{Config, RngAlgorithm, TestRng, TestRunner}; use crate::Srgb8; use crate::appearance::{ - AppearanceBindings, AppearanceGraphSpec, BindingError, ColorInputId, CompositionProfileV1, - OccurrenceId, OccurrenceSpec, PaintId, PaintSpec, PointOpacityError, PointOpacityOverSurfaceV1, - ResolvedOccurrence, SurfaceId, SurfaceInputPortId, SurfaceSpec, + AppearanceBindings, AppearanceGraphSpec, BindingError, CompositionProfileV1, + EncodedPointPaintValueV1, OccurrenceId, OccurrenceSpec, PaintId, PaintInputId, PaintSpec, + PointOpacityError, PointOpacityOverSurfaceV1, ResolvedOccurrence, SurfaceId, + SurfaceInputPortId, SurfaceSpec, }; use crate::lcs_occurrence::ColorSignal; use crate::observation::{ @@ -305,22 +306,25 @@ fn prepare_ordered<'owner>( } #[test] -fn authored_color_and_observed_surface_ports_are_distinct_through_execution() { +fn authored_paint_and_observed_surface_ports_are_distinct_through_execution() { let _sealed_adapter_contract: fn( [u8; 3], f64, [u8; 3], ) -> Result = PointOpacityOverSurfaceV1::evaluate; - let color = ColorInputId::new(7); + let paint_input = PaintInputId::new(7); let surface_port = SurfaceInputPortId::new(7); let paint = PaintId::new(1); let surface = SurfaceId::new(1); let occurrence = OccurrenceId::new(1); let graph = AppearanceGraphSpec::new( - vec![color], + vec![paint_input], vec![surface_port], vec![], - vec![PaintSpec::Solid { id: paint, color }], + vec![PaintSpec::Input { + id: paint, + input: paint_input, + }], vec![SurfaceSpec::Input { id: surface, port: surface_port, @@ -337,7 +341,10 @@ fn authored_color_and_observed_surface_ports_are_distinct_through_execution() { let evaluation = graph .evaluate(&AppearanceBindings::new( - vec![(color, Srgb8::new([1, 2, 3]))], + vec![( + paint_input, + EncodedPointPaintValueV1::opaque(Srgb8::new([1, 2, 3])), + )], vec![(surface_port, Srgb8::new([240, 241, 242]))], vec![], )) @@ -348,7 +355,10 @@ fn authored_color_and_observed_surface_ports_are_distinct_through_execution() { ); assert_eq!( graph.evaluate(&AppearanceBindings::new( - vec![(color, Srgb8::new([1, 2, 3]))], + vec![( + paint_input, + EncodedPointPaintValueV1::opaque(Srgb8::new([1, 2, 3])), + )], vec![], vec![], )), diff --git a/crates/labcolors-core/src/point_support_tests.rs b/crates/labcolors-core/src/point_support_tests.rs index 000a843b..f8803ce3 100644 --- a/crates/labcolors-core/src/point_support_tests.rs +++ b/crates/labcolors-core/src/point_support_tests.rs @@ -1,6 +1,7 @@ use crate::Srgb8; use crate::appearance::{ - EncodedPointPaintV1, OccurrenceId, PaintId, PhysicalProgramIdentityV1, SurfaceInputPortId, + EncodedPointPaintV1, EncodedPointPaintValueV1, OccurrenceId, PaintId, + PhysicalProgramIdentityV1, SurfaceInputPortId, }; use crate::composition::{AdmittedOpacityV1, CompositionProfileV1}; use crate::lcs_occurrence::ColorSignal; @@ -30,10 +31,12 @@ const PAINT_A: PaintId = PaintId::new(41); const PAINT_B: PaintId = PaintId::new(42); fn paint(id: PaintId, source: [u8; 3], opacity: f64) -> EncodedPointPaintV1 { - EncodedPointPaintV1::from_admitted( + EncodedPointPaintV1::from_value( id, - Srgb8::new(source), - AdmittedOpacityV1::new(opacity).unwrap(), + EncodedPointPaintValueV1::from_admitted( + Srgb8::new(source), + AdmittedOpacityV1::new(opacity).unwrap(), + ), ) } @@ -418,7 +421,7 @@ fn exact_wcag_and_stability_are_independent_axes_and_baseline_binds_once() { ); assert_eq!( report.physical_program(), - PhysicalProgramIdentityV1::SolidOpacityOverSurfaceEncodedSrgb8V1 + PhysicalProgramIdentityV1::InputOpacityOverSurfaceEncodedSrgb8V1 ); let cell = report.cells().next().unwrap(); assert_eq!(cell.provenance(), &[ScenarioId::new(44)]); diff --git a/crates/labcolors-core/src/program_session.rs b/crates/labcolors-core/src/program_session.rs index fb63714c..60a224ce 100644 --- a/crates/labcolors-core/src/program_session.rs +++ b/crates/labcolors-core/src/program_session.rs @@ -28,12 +28,13 @@ use std::rc::{Rc, Weak}; use crate::Srgb8; use crate::appearance::{ AdmittedAppearanceBindings, AppearanceBindings, AppearanceEvaluationView, AppearanceGraphSpec, - AppearanceWorkspace, BindingError, ColorInputId, CompileError, CompiledAppearanceGraph, - CompiledColorInputSlotV1, CompiledOccurrenceSlotV1, CompiledPaintSlotV1, - CompiledPointPresentationPathV1, EncodedPointPaintV1, ExactFinalOwnedPointDomainV1, - OccurrenceId, OccurrenceSpec, OpacityInputId, PaintId, PaintSpec, - PointOccurrenceAbsenceReleaseV1, PointOccurrenceAbsenceStepV1, PointOccurrenceAbsenceSummaryV1, - PointPresentationPathErrorV1, SurfaceId, SurfaceInputPortId, SurfaceSpec, + AppearanceWorkspace, BindingError, CompileError, CompiledAppearanceGraph, + CompiledOccurrenceSlotV1, CompiledPaintInputSlotV1, CompiledPaintSlotV1, + CompiledPointPresentationPathV1, EncodedPointPaintV1, EncodedPointPaintValueV1, + ExactFinalOwnedPointDomainV1, OccurrenceId, OccurrenceSpec, OpacityInputId, PaintId, + PaintInputId, PaintSpec, PointOccurrenceAbsenceReleaseV1, PointOccurrenceAbsenceStepV1, + PointOccurrenceAbsenceSummaryV1, PointPresentationPathErrorV1, SurfaceId, SurfaceInputPortId, + SurfaceSpec, }; use crate::clean_set::{ ClosedRejectedBlueIntervalV1, ExactNominalSrgb8CleanSetDecisionV1, ExactNominalSrgb8CleanSetV1, @@ -1467,7 +1468,7 @@ impl CompiledPointPresentationsV1 { } struct CompiledFiniteTargetV1 { - binding: CompiledColorInputSlotV1, + binding: CompiledPaintInputSlotV1, candidates: Box<[ColorSignal]>, } @@ -3156,7 +3157,10 @@ where .ok_or(ProgramSessionEvaluationError::InternalInvariant)?; runtime .bindings - .overwrite_color_at(target.binding, candidate.srgb8()) + .overwrite_paint_input_at( + target.binding, + EncodedPointPaintValueV1::opaque(candidate.srgb8()), + ) .map_err(map_program_execution_binding_error)?; } Ok(()) @@ -4151,7 +4155,7 @@ fn compile_targets( > { struct CanonicalFiniteTargetV1<'a> { id: TargetId, - binding: CompiledColorInputSlotV1, + binding: CompiledPaintInputSlotV1, candidates: &'a [TargetCandidateV1], } @@ -4167,7 +4171,7 @@ fn compile_targets( return Err(ProgramCompileError::EmptyTargetDomain { target: target.id }); } let binding = graph - .bind_color_input(target_color_input_id(target.id)) + .bind_paint_input(target_paint_input_id(target.id)) .ok_or(ProgramCompileError::InternalInvariant)?; candidates.sort_unstable_by_key(|candidate| candidate.id); if let Some(candidate) = candidates @@ -4699,8 +4703,8 @@ pub(crate) fn canonical_surface_input_port_sequence_matches( actual.into_iter().eq(expected.iter().copied()) } -const fn target_color_input_id(target: TargetId) -> ColorInputId { - ColorInputId::new(target.value()) +const fn target_paint_input_id(target: TargetId) -> PaintInputId { + PaintInputId::new(target.value()) } fn try_collect_program( @@ -4722,12 +4726,12 @@ where Evaluation: ProgramConstraintEvaluatorSetV1, ProgramConstraintInvocationOf: Copy, { - let colors = try_collect_program( + let paint_inputs = try_collect_program( program.targets.len(), program .targets .iter() - .map(|target| target_color_input_id(target.id)), + .map(|target| target_paint_input_id(target.id)), )?; let surface_inputs = try_collect_program( program.observation_group.surface_input_ports.len(), @@ -4744,9 +4748,9 @@ where let paints = try_collect_program( program.paints.len(), program.paints.iter().map(|paint| match *paint { - Paint::Solid { id, target } => PaintSpec::Solid { + Paint::Solid { id, target } => PaintSpec::Input { id, - color: target_color_input_id(target), + input: target_paint_input_id(target), }, Paint::Opacity { id, @@ -4782,7 +4786,7 @@ where }), )?; Ok(AppearanceGraphSpec::new( - colors, + paint_inputs, surface_inputs, opacities, paints, @@ -4798,8 +4802,8 @@ where Evaluation: ProgramConstraintEvaluatorSetV1, ProgramConstraintInvocationOf: Copy, { - let mut colors = Vec::new(); - colors + let mut paint_inputs = Vec::new(); + paint_inputs .try_reserve_exact(program.targets.len()) .map_err(|_| ProgramCompileError::ResourceExhausted)?; for target in &program.targets { @@ -4807,9 +4811,9 @@ where .sources .binary_search_by_key(&target.source, |source| source.id) .map_err(|_| ProgramCompileError::InternalInvariant)?; - colors.push(( - target_color_input_id(target.id), - program.sources[source_index].signal.srgb8(), + paint_inputs.push(( + target_paint_input_id(target.id), + EncodedPointPaintValueV1::opaque(program.sources[source_index].signal.srgb8()), )); } let surfaces = try_collect_program( @@ -4827,12 +4831,12 @@ where .iter() .map(|input| (input.id, input.value)), )?; - Ok(AppearanceBindings::new(colors, surfaces, opacities)) + Ok(AppearanceBindings::new(paint_inputs, surfaces, opacities)) } fn map_compile_error(error: CompileError) -> ProgramCompileError { match error { - CompileError::DuplicateColorInput { .. } => ProgramCompileError::InternalInvariant, + CompileError::DuplicatePaintInput { .. } => ProgramCompileError::InternalInvariant, CompileError::DuplicateOpacityInput { input } => { ProgramCompileError::DuplicateOpacityInput { input } } @@ -4846,7 +4850,7 @@ fn map_compile_error(error: CompileError) -> ProgramCompileError { CompileError::DuplicateOccurrence { occurrence } => { ProgramCompileError::DuplicateOccurrence { occurrence } } - CompileError::MissingPaintColorInput { .. } => ProgramCompileError::InternalInvariant, + CompileError::MissingPaintInput { .. } => ProgramCompileError::InternalInvariant, CompileError::MissingPaintSource { paint, source } => { ProgramCompileError::MissingPaintSource { paint, source } } diff --git a/packages/colors/bench/wasm.json b/packages/colors/bench/wasm.json index a6747cef..989c586e 100644 --- a/packages/colors/bench/wasm.json +++ b/packages/colors/bench/wasm.json @@ -19,13 +19,13 @@ "command": "CARGO_ENCODED_RUSTFLAGS= wasm-pack build crates/labcolors-wasm --release --target web --out-dir ../../packages/colors/pkg --out-name labcolors --locked" }, "measurement": { - "source": "github-actions-run-30214988060", + "source": "github-actions-run-30324408912", "platform": "linux-x64", - "rawBytes": 376707 + "rawBytes": 376675 }, "policy": { - "maxRawBytes": 376707, - "basis": "program-content-identity", + "maxRawBytes": 376675, + "basis": "v3a-atomic-paint-input", "gzip": "diagnostic-only" } } diff --git a/scripts/check-wasm-size-budget.mjs b/scripts/check-wasm-size-budget.mjs index fe920406..e3a95992 100644 --- a/scripts/check-wasm-size-budget.mjs +++ b/scripts/check-wasm-size-budget.mjs @@ -14,7 +14,7 @@ export const DEFAULT_BUDGET = resolve( "packages/colors/bench/wasm.json", ); export const WASM_BUDGET_FILE_SHA256 = - "46c8830fadaa96c50d784bff41329177b4bf8742dbd8d1b1bb175b3150c55107"; + "3d548ed9c77adb1a99eaa37c8a3f9ff06526adaa18cee4085023d13e6f6731b7"; const SCHEMA_VERSION = 1; const CANONICAL_ARTIFACT = "packages/colors/pkg/labcolors_bg.wasm"; diff --git a/scripts/verify_point_support_surplus.py b/scripts/verify_point_support_surplus.py index 89604b05..16f023be 100755 --- a/scripts/verify_point_support_surplus.py +++ b/scripts/verify_point_support_surplus.py @@ -58,7 +58,7 @@ SOURCE_BINDING_LAW = "point-support-rust-whole-file-semantic-cone-v2" SOURCE_BINDING_DOMAIN = b"labcolors.point-support.rust-whole-file-semantic-cone.v2" EXPECTED_SOURCE_CAPSULE_SHA256 = ( - "472d7e40538fc8864b66ddc65ab45728183b3a8cd309efa49011f3ce2b9f6619" + "de9e26c5da5d24cd1a76092c5e5caea02fe69f1f18d367fbf0ea7635bee819a9" ) EXPECTED_Q55_PROOF_SHA256 = ( "ac59cf89503170c789223b91d775213a19d4e571ef930f2ea609fcd51b14defd"