зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1550640 - P3: Replace bincode with peek-poke. r=Gankro
Replace `serde`-derived `bincode` with custom binary serialization/deserialization that generates more efficient code at rustc `opt-level = 2`. Differential Revision: https://phabricator.services.mozilla.com/D32782 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
73ed10d490
Коммит
866dcdad61
|
@ -1030,7 +1030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "euclid"
|
||||
version = "0.19.5"
|
||||
version = "0.19.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1715,7 +1715,7 @@ version = "0.0.1"
|
|||
dependencies = [
|
||||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashglobe 0.1.0",
|
||||
"selectors 0.21.0",
|
||||
"servo_arc 0.1.1",
|
||||
|
@ -2191,6 +2191,25 @@ dependencies = [
|
|||
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peek-poke"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"peek-poke-derive 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peek-poke-derive"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
|
@ -2252,7 +2271,7 @@ version = "0.13.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -2926,7 +2945,7 @@ dependencies = [
|
|||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fallible 0.0.1",
|
||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashglobe 0.1.0",
|
||||
|
@ -2987,7 +3006,7 @@ dependencies = [
|
|||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of 0.0.1",
|
||||
"malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3598,7 +3617,7 @@ dependencies = [
|
|||
"core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3635,8 +3654,9 @@ dependencies = [
|
|||
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"peek-poke 0.2.0",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)",
|
||||
|
@ -3653,7 +3673,7 @@ dependencies = [
|
|||
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3750,7 +3770,7 @@ name = "wr_malloc_size_of"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3948,7 +3968,7 @@ dependencies = [
|
|||
"checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed"
|
||||
"checksum env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0561146661ae44c579e993456bc76d11ce1e0c7d745e57b2fa7146b6e49fa2ad"
|
||||
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
|
||||
"checksum euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a7698bdda3d7444a79d33bdc96e8b518d44ea3ff101d8492a6ca1207b886ea"
|
||||
"checksum euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)" = "596b99621b9477e7a5f94d2d8dd13a9c5c302ac358b822c67a42b6f1054450e1"
|
||||
"checksum euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcb84c18ea5037a1c5a23039b4ff29403abce2e0d6b1daa11cf0bde2b30be15"
|
||||
"checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7"
|
||||
"checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596"
|
||||
|
|
|
@ -401,7 +401,7 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -411,7 +411,7 @@ version = "0.13.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -428,7 +428,7 @@ dependencies = [
|
|||
name = "direct-composition"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender 0.60.0",
|
||||
|
@ -485,7 +485,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "euclid"
|
||||
version = "0.19.5"
|
||||
version = "0.19.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -499,7 +499,7 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -891,7 +891,7 @@ version = "0.12.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1046,7 +1046,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1180,7 +1180,7 @@ dependencies = [
|
|||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1195,7 +1195,7 @@ name = "pathfinder_gfx_utils"
|
|||
version = "0.2.0"
|
||||
source = "git+https://github.com/pcwalton/pathfinder?branch=webrender#e8805413321edf85870deee5678751746ed61316"
|
||||
dependencies = [
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1208,7 +1208,7 @@ dependencies = [
|
|||
"bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"half 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lyon_geom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1229,6 +1229,25 @@ dependencies = [
|
|||
"serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peek-poke"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"peek-poke-derive 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peek-poke-derive"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "1.0.1"
|
||||
|
@ -1245,7 +1264,7 @@ version = "0.13.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -1281,7 +1300,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.3"
|
||||
version = "0.6.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1573,7 +1592,7 @@ version = "1.0.88"
|
|||
source = "git+https://github.com/servo/serde?branch=deserialize_from_enums10#84b2795d2a7b5312125a99b1ef11c67fd8d17c35"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1705,7 +1724,7 @@ version = "0.15.30"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1715,7 +1734,7 @@ version = "0.10.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -1957,7 +1976,7 @@ dependencies = [
|
|||
"core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cstr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1996,7 +2015,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2015,9 +2034,10 @@ dependencies = [
|
|||
"core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"peek-poke 0.2.0",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)",
|
||||
|
@ -2106,7 +2126,7 @@ name = "wr_malloc_size_of"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2123,7 +2143,7 @@ dependencies = [
|
|||
"crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"font-loader 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2268,7 +2288,7 @@ dependencies = [
|
|||
"checksum dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0bd1369e02db5e9b842a9b67bce8a2fcc043beafb2ae8a799dd482d46ea1ff0d"
|
||||
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
|
||||
"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a"
|
||||
"checksum euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a7698bdda3d7444a79d33bdc96e8b518d44ea3ff101d8492a6ca1207b886ea"
|
||||
"checksum euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)" = "596b99621b9477e7a5f94d2d8dd13a9c5c302ac358b822c67a42b6f1054450e1"
|
||||
"checksum euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcb84c18ea5037a1c5a23039b4ff29403abce2e0d6b1daa11cf0bde2b30be15"
|
||||
"checksum expat-sys 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c470ccb972f2088549b023db8029ed9da9426f5affbf9b62efff7009ab8ed5b1"
|
||||
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
|
@ -2360,7 +2380,7 @@ dependencies = [
|
|||
"checksum proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)" = "d3797b7142c9aa74954e351fc089bbee7958cebbff6bf2815e7ffff0b19f547d"
|
||||
"checksum procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9a1574a51c3fd37b26d2c0032b649d08a7d51d4cca9c41bbc5bf7118fa4509d0"
|
||||
"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
|
||||
"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035"
|
||||
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
|
||||
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
|
||||
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
|
||||
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
||||
|
|
|
@ -15,4 +15,4 @@ panic = "abort"
|
|||
panic = "abort"
|
||||
|
||||
[patch.crates-io]
|
||||
serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums10" }
|
||||
serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums10", feature="deserialize_in_place" }
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "peek-poke"
|
||||
version = "0.2.0"
|
||||
authors = ["Dan Glastonbury <dan.glastonbury@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
euclid = { version = "0.19", optional = true }
|
||||
peek-poke-derive = { version = "0.2", path = "./peek-poke-derive", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["derive"]
|
||||
derive = ["peek-poke-derive"]
|
||||
extras = ["derive", "euclid"]
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,44 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Daniel Glastonbury
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
This work incorporates work covered by the following copyright and permission
|
||||
notice:
|
||||
|
||||
Copyright (c) 2019 Devashish Dixit
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,54 @@
|
|||
# Peeks, Pokes, and Pointers
|
||||
|
||||
Peek from and poke structures into byte slices.
|
||||
|
||||
## Benchmark
|
||||
|
||||
Below are the benchmark results of comparison between `peek-poke` and `bincode` serializing and deserializing same `struct`:
|
||||
```
|
||||
struct MyPeekPokeStruct {
|
||||
a: u8,
|
||||
b: u16,
|
||||
c: MyPeekPokeEnum,
|
||||
d: Option<usize>,
|
||||
}
|
||||
|
||||
enum MyPeekPokeEnum {
|
||||
Variant1,
|
||||
Variant2(u16),
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
Benchmarking struct::serialize/peek_poke::poke_into: Collecting 100 samples in struct::serialize/peek_poke::poke_into
|
||||
time: [2.7267 ns 2.7321 ns 2.7380 ns]
|
||||
|
||||
Benchmarking struct::serialize/bincode::serialize: Collecting 100 samples in est struct::serialize/bincode::serialize
|
||||
time: [31.264 ns 31.326 ns 31.389 ns]
|
||||
|
||||
Benchmarking struct::deserialize/peek_poke::peek_from: Collecting 100 samples struct::deserialize/peek_poke::peek_from
|
||||
time: [5.3544 ns 5.3672 ns 5.3817 ns]
|
||||
|
||||
Benchmarking struct::deserialize/bincode::deserialize: Collecting 100 samples in struct::deserialize/bincode::deserialize
|
||||
time: [25.155 ns 26.439 ns 27.661 ns]
|
||||
```
|
||||
|
||||
You can run benchmarks by running following command:
|
||||
```
|
||||
cargo bench
|
||||
```
|
||||
|
||||
## License
|
||||
[license]: #license
|
||||
|
||||
Licensed under either of
|
||||
- Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license (http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
see [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT) for details.
|
||||
|
||||
## Contribution
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as
|
||||
defined in the Apache-2.0 license, shall be dual licensed as about, without any additional terms or conditions.
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "peek-poke-derive"
|
||||
version = "0.2.0"
|
||||
authors = ["Dan Glastonbury <dan.glastonbury@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "0.4"
|
||||
quote = "0.6"
|
||||
syn = "0.15"
|
||||
synstructure = "0.10"
|
||||
unicode-xid = "0.1"
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,44 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Daniel Glastonbury
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
This work incorporates work covered by the following copyright and permission
|
||||
notice:
|
||||
|
||||
Copyright (c) 2019 Devashish Dixit
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,54 @@
|
|||
# Peeks, Pokes, and Pointers
|
||||
|
||||
Peek from and poke structures into byte slices.
|
||||
|
||||
## Benchmark
|
||||
|
||||
Below are the benchmark results of comparison between `peek-poke` and `bincode` serializing and deserializing same `struct`:
|
||||
```
|
||||
struct MyPeekPokeStruct {
|
||||
a: u8,
|
||||
b: u16,
|
||||
c: MyPeekPokeEnum,
|
||||
d: Option<usize>,
|
||||
}
|
||||
|
||||
enum MyPeekPokeEnum {
|
||||
Variant1,
|
||||
Variant2(u16),
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
Benchmarking struct::serialize/peek_poke::poke_into: Collecting 100 samples in struct::serialize/peek_poke::poke_into
|
||||
time: [2.7267 ns 2.7321 ns 2.7380 ns]
|
||||
|
||||
Benchmarking struct::serialize/bincode::serialize: Collecting 100 samples in est struct::serialize/bincode::serialize
|
||||
time: [31.264 ns 31.326 ns 31.389 ns]
|
||||
|
||||
Benchmarking struct::deserialize/peek_poke::peek_from: Collecting 100 samples struct::deserialize/peek_poke::peek_from
|
||||
time: [5.3544 ns 5.3672 ns 5.3817 ns]
|
||||
|
||||
Benchmarking struct::deserialize/bincode::deserialize: Collecting 100 samples in struct::deserialize/bincode::deserialize
|
||||
time: [25.155 ns 26.439 ns 27.661 ns]
|
||||
```
|
||||
|
||||
You can run benchmarks by running following command:
|
||||
```
|
||||
cargo bench
|
||||
```
|
||||
|
||||
## License
|
||||
[license]: #license
|
||||
|
||||
Licensed under either of
|
||||
- Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license (http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
see [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT) for details.
|
||||
|
||||
## Contribution
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as
|
||||
defined in the Apache-2.0 license, shall be dual licensed as about, without any additional terms or conditions.
|
|
@ -0,0 +1,259 @@
|
|||
// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{Ident, Index, TraitBound};
|
||||
use synstructure::{decl_derive, Structure, BindStyle, AddBounds};
|
||||
use unicode_xid::UnicodeXID;
|
||||
|
||||
// Internal method for sanitizing an identifier for hygiene purposes.
|
||||
fn sanitize_ident(s: &str) -> Ident {
|
||||
let mut res = String::with_capacity(s.len());
|
||||
for mut c in s.chars() {
|
||||
if !UnicodeXID::is_xid_continue(c) {
|
||||
c = '_'
|
||||
}
|
||||
// Deduplicate consecutive _ characters.
|
||||
if res.ends_with('_') && c == '_' {
|
||||
continue;
|
||||
}
|
||||
res.push(c);
|
||||
}
|
||||
Ident::new(&res, Span::call_site())
|
||||
}
|
||||
|
||||
/// Calculates size type for number of variants (used for enums)
|
||||
fn get_discriminant_size_type(len: usize) -> TokenStream {
|
||||
if len <= <u8>::max_value() as usize {
|
||||
quote! { u8 }
|
||||
} else if len <= <u16>::max_value() as usize {
|
||||
quote! { u16 }
|
||||
} else {
|
||||
quote! { u32 }
|
||||
}
|
||||
}
|
||||
|
||||
fn is_struct(s: &Structure) -> bool {
|
||||
// a single variant with no prefix is 'struct'
|
||||
match &s.variants()[..] {
|
||||
[v] if v.prefix.is_none() => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn derive_max_size(s: &Structure) -> TokenStream {
|
||||
let max_size = s.variants().iter().fold(quote!(0), |acc, vi| {
|
||||
let variant_size = vi.bindings().iter().fold(quote!(0), |acc, bi| {
|
||||
// compute size of each variant by summing the sizes of its bindings
|
||||
let ty = &bi.ast().ty;
|
||||
quote!(#acc + <#ty>::max_size())
|
||||
});
|
||||
|
||||
// find the maximum of each variant
|
||||
quote! {
|
||||
max(#acc, #variant_size)
|
||||
}
|
||||
});
|
||||
|
||||
let body = if is_struct(s) {
|
||||
max_size
|
||||
} else {
|
||||
let discriminant_size_type = get_discriminant_size_type(s.variants().len());
|
||||
quote! {
|
||||
#discriminant_size_type ::max_size() + #max_size
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
use std::cmp::max;
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn derive_peek_from_for_enum(s: &mut Structure) -> TokenStream {
|
||||
assert!(!is_struct(s));
|
||||
s.bind_with(|_| BindStyle::Move);
|
||||
|
||||
let discriminant_size_type = get_discriminant_size_type(s.variants().len());
|
||||
let body = s
|
||||
.variants()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.fold(quote!(), |acc, (i, vi)| {
|
||||
let bindings = vi
|
||||
.bindings()
|
||||
.iter()
|
||||
.map(|bi| quote!(#bi))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let variant_pat = Index::from(i);
|
||||
let poke_exprs = bindings.iter().fold(quote!(), |acc, bi| {
|
||||
quote! {
|
||||
#acc
|
||||
let (#bi, bytes) = peek_poke::peek_from_default(bytes);
|
||||
}
|
||||
});
|
||||
let construct = vi.construct(|_, i| {
|
||||
let bi = &bindings[i];
|
||||
quote!(#bi)
|
||||
});
|
||||
|
||||
quote! {
|
||||
#acc
|
||||
#variant_pat => {
|
||||
#poke_exprs
|
||||
*output = #construct;
|
||||
bytes
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#[inline(always)]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
let (variant, bytes) = peek_poke::peek_from_default::<#discriminant_size_type>(bytes);
|
||||
match variant {
|
||||
#body
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn derive_peek_from_for_struct(s: &mut Structure) -> TokenStream {
|
||||
assert!(is_struct(&s));
|
||||
|
||||
s.variants_mut()[0].bind_with(|_| BindStyle::RefMut);
|
||||
let pat = s.variants()[0].pat();
|
||||
let peek_exprs = s.variants()[0].bindings().iter().fold(quote!(), |acc, bi| {
|
||||
let ty = &bi.ast().ty;
|
||||
quote! {
|
||||
#acc
|
||||
let bytes = <#ty>::peek_from(bytes, #bi);
|
||||
}
|
||||
});
|
||||
|
||||
let body = quote! {
|
||||
#pat => {
|
||||
#peek_exprs
|
||||
bytes
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[inline(always)]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
match &mut (*output) {
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn derive_poke_into(s: &Structure) -> TokenStream {
|
||||
let is_struct = is_struct(&s);
|
||||
let discriminant_size_type = get_discriminant_size_type(s.variants().len());
|
||||
let body = s
|
||||
.variants()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.fold(quote!(), |acc, (i, vi)| {
|
||||
let init = if !is_struct {
|
||||
let index = Index::from(i);
|
||||
quote! {
|
||||
let bytes = #discriminant_size_type::poke_into(&#index, bytes);
|
||||
}
|
||||
} else {
|
||||
quote!()
|
||||
};
|
||||
let variant_pat = vi.pat();
|
||||
let poke_exprs = vi.bindings().iter().fold(init, |acc, bi| {
|
||||
quote! {
|
||||
#acc
|
||||
let bytes = #bi.poke_into(bytes);
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#acc
|
||||
#variant_pat => {
|
||||
#poke_exprs
|
||||
bytes
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#[inline(always)]
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
match &*self {
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn peek_poke_derive(mut s: Structure) -> TokenStream {
|
||||
s.binding_name(|_, i| Ident::new(&format!("__self_{}", i), Span::call_site()));
|
||||
|
||||
let max_size_fn = derive_max_size(&s);
|
||||
let poke_into_fn = derive_poke_into(&s);
|
||||
let peek_from_fn = if is_struct(&s) {
|
||||
derive_peek_from_for_struct(&mut s)
|
||||
} else {
|
||||
derive_peek_from_for_enum(&mut s)
|
||||
};
|
||||
|
||||
let poke_impl = s.gen_impl(quote! {
|
||||
extern crate peek_poke;
|
||||
|
||||
gen unsafe impl peek_poke::Poke for @Self {
|
||||
#max_size_fn
|
||||
#poke_into_fn
|
||||
}
|
||||
});
|
||||
|
||||
// To implement `fn peek_from` we require that types implement `Default`
|
||||
// trait to create temporary values. This code does the addition all
|
||||
// manually until https://github.com/mystor/synstructure/issues/24 is fixed.
|
||||
let default_trait = syn::parse_str::<TraitBound>("::std::default::Default").unwrap();
|
||||
let peek_trait = syn::parse_str::<TraitBound>("peek_poke::Peek").unwrap();
|
||||
|
||||
let ast = s.ast();
|
||||
let name = &ast.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
|
||||
let mut where_clause = where_clause.cloned();
|
||||
s.add_trait_bounds(&default_trait, &mut where_clause, AddBounds::Generics);
|
||||
s.add_trait_bounds(&peek_trait, &mut where_clause, AddBounds::Generics);
|
||||
|
||||
let dummy_const: Ident = sanitize_ident(&format!("_DERIVE_peek_poke_Peek_FOR_{}", name));
|
||||
|
||||
let peek_impl = quote! {
|
||||
#[allow(non_upper_case_globals)]
|
||||
const #dummy_const: () = {
|
||||
extern crate peek_poke;
|
||||
|
||||
impl #impl_generics peek_poke::Peek for #name #ty_generics #where_clause {
|
||||
#peek_from_fn
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
quote! {
|
||||
#poke_impl
|
||||
#peek_impl
|
||||
}
|
||||
}
|
||||
|
||||
decl_derive!([PeekPoke] => peek_poke_derive);
|
|
@ -0,0 +1,170 @@
|
|||
// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::{Peek, Poke};
|
||||
use euclid::{TypedPoint2D, TypedRect, TypedSideOffsets2D, TypedSize2D, TypedTransform3D, TypedVector2D};
|
||||
|
||||
unsafe impl<T: Poke, U> Poke for TypedPoint2D<T, U> {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
2 * T::max_size()
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
let bytes = self.x.poke_into(bytes);
|
||||
let bytes = self.y.poke_into(bytes);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
impl<T: Peek, U> Peek for TypedPoint2D<T, U> {
|
||||
#[inline(always)]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
let bytes = T::peek_from(bytes, &mut (*output).x);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).y);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Poke, U> Poke for TypedRect<T, U> {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
TypedPoint2D::<T, U>::max_size() + TypedSize2D::<T, U>::max_size()
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
let bytes = self.origin.poke_into(bytes);
|
||||
let bytes = self.size.poke_into(bytes);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
impl<T: Peek, U> Peek for TypedRect<T, U> {
|
||||
#[inline(always)]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
let bytes = TypedPoint2D::<T, U>::peek_from(bytes, &mut (*output).origin);
|
||||
let bytes = TypedSize2D::<T, U>::peek_from(bytes, &mut (*output).size);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Poke, U> Poke for TypedSideOffsets2D<T, U> {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
4 * T::max_size()
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
let bytes = self.top.poke_into(bytes);
|
||||
let bytes = self.right.poke_into(bytes);
|
||||
let bytes = self.bottom.poke_into(bytes);
|
||||
let bytes = self.left.poke_into(bytes);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
impl<T: Peek, U> Peek for TypedSideOffsets2D<T, U> {
|
||||
#[inline(always)]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
let bytes = T::peek_from(bytes, &mut (*output).top);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).right);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).bottom);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).left);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Poke, U> Poke for TypedSize2D<T, U> {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
2 * T::max_size()
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
let bytes = self.width.poke_into(bytes);
|
||||
let bytes = self.height.poke_into(bytes);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
impl<T: Peek, U> Peek for TypedSize2D<T, U> {
|
||||
#[inline(always)]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
let bytes = T::peek_from(bytes, &mut (*output).width);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).height);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Poke, S, D> Poke for TypedTransform3D<T, S, D> {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
16 * T::max_size()
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
let bytes = self.m11.poke_into(bytes);
|
||||
let bytes = self.m12.poke_into(bytes);
|
||||
let bytes = self.m13.poke_into(bytes);
|
||||
let bytes = self.m14.poke_into(bytes);
|
||||
let bytes = self.m21.poke_into(bytes);
|
||||
let bytes = self.m22.poke_into(bytes);
|
||||
let bytes = self.m23.poke_into(bytes);
|
||||
let bytes = self.m24.poke_into(bytes);
|
||||
let bytes = self.m31.poke_into(bytes);
|
||||
let bytes = self.m32.poke_into(bytes);
|
||||
let bytes = self.m33.poke_into(bytes);
|
||||
let bytes = self.m34.poke_into(bytes);
|
||||
let bytes = self.m41.poke_into(bytes);
|
||||
let bytes = self.m42.poke_into(bytes);
|
||||
let bytes = self.m43.poke_into(bytes);
|
||||
let bytes = self.m44.poke_into(bytes);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
impl<T: Peek, S, D> Peek for TypedTransform3D<T, S, D> {
|
||||
#[inline(always)]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m11);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m12);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m13);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m14);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m21);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m22);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m23);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m24);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m31);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m32);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m33);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m34);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m41);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m42);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m43);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).m44);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Poke, U> Poke for TypedVector2D<T, U> {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
2 * T::max_size()
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
let bytes = self.x.poke_into(bytes);
|
||||
let bytes = self.y.poke_into(bytes);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
impl<T: Peek, U> Peek for TypedVector2D<T, U> {
|
||||
#[inline(always)]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
let bytes = T::peek_from(bytes, &mut (*output).x);
|
||||
let bytes = T::peek_from(bytes, &mut (*output).y);
|
||||
bytes
|
||||
}
|
||||
}
|
|
@ -0,0 +1,427 @@
|
|||
// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Fast binary serialization and deserialization for types with a known maximum size.
|
||||
//!
|
||||
//! ## Binary Encoding Scheme
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! ## Comparison to bincode
|
||||
|
||||
#[cfg(feature = "derive")]
|
||||
pub use peek_poke_derive::*;
|
||||
|
||||
use core::{marker::PhantomData, mem::size_of, slice};
|
||||
use crate::{slice_ext::*, vec_ext::*};
|
||||
|
||||
mod slice_ext;
|
||||
mod vec_ext;
|
||||
|
||||
union MaybeUninitShim<T: Copy> {
|
||||
uninit: (),
|
||||
init: T,
|
||||
}
|
||||
|
||||
/// Peek helper for constructing a `T` by `Copy`ing into an uninitialized stack
|
||||
/// allocation.
|
||||
pub unsafe fn peek_from_uninit<T: Copy + Peek>(bytes: *const u8) -> (T, *const u8) {
|
||||
let mut val = MaybeUninitShim { uninit: () };
|
||||
let bytes = <T>::peek_from(bytes, &mut val.init);
|
||||
(val.init, bytes)
|
||||
}
|
||||
|
||||
/// Peek helper for constructing a `T` by `Default` initialized stack
|
||||
/// allocation.
|
||||
pub unsafe fn peek_from_default<T: Default + Peek>(bytes: *const u8) -> (T, *const u8) {
|
||||
let mut val = T::default();
|
||||
let bytes = <T>::peek_from(bytes, &mut val);
|
||||
(val, bytes)
|
||||
}
|
||||
|
||||
/// Peek inplace a `T` from a slice of bytes, returning a slice of the remaining
|
||||
/// bytes. `src` must contain at least `T::max_size()` bytes.
|
||||
///
|
||||
/// [`ensure_red_zone`] can be used to add required padding.
|
||||
pub fn peek_from_slice<'a, T: Peek>(src: &'a [u8], dst: &mut T) -> &'a [u8] {
|
||||
unsafe {
|
||||
// If src.len() == T::max_size() then src is at the start of the red-zone.
|
||||
assert!(T::max_size() < src.len());
|
||||
let end_ptr = T::peek_from(src.as_ptr(), dst);
|
||||
let len = end_ptr as usize - src.as_ptr() as usize;
|
||||
// Did someone break the T::peek_from() can't read more than T::max_size()
|
||||
// bytes contract?
|
||||
assert!(len <= src.len());
|
||||
slice::from_raw_parts(end_ptr, src.len() - len)
|
||||
}
|
||||
}
|
||||
|
||||
/// Poke helper to insert a serialized version of `src` at the beginning for `dst`.
|
||||
pub fn poke_inplace_slice<T: Poke>(src: &T, dst: &mut [u8]) {
|
||||
assert!(T::max_size() <= dst.len());
|
||||
unsafe {
|
||||
src.poke_into(dst.as_mut_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
/// Poke helper to append a serialized version of `src` to the end of `dst`.
|
||||
pub fn poke_into_vec<T: Poke>(src: &T, dst: &mut Vec<u8>) {
|
||||
dst.reserve(T::max_size());
|
||||
unsafe {
|
||||
let ptr = dst.as_end_mut_ptr();
|
||||
let end_ptr = src.poke_into(ptr);
|
||||
dst.set_end_ptr(end_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Is returning the len of the iterator of any practical use?
|
||||
pub fn poke_extend_vec<I>(src: I, dst: &mut Vec<u8>) -> usize
|
||||
where
|
||||
I: ExactSizeIterator,
|
||||
I::Item: Poke,
|
||||
{
|
||||
let len = src.len();
|
||||
let max_size = len * I::Item::max_size();
|
||||
dst.reserve(max_size);
|
||||
unsafe {
|
||||
let ptr = dst.as_end_mut_ptr();
|
||||
// Guard against the possibility of a misbehaved implementation of
|
||||
// ExactSizeIterator by writing at most `len` items.
|
||||
let end_ptr = src.take(len).fold(ptr, |ptr, item| item.poke_into(ptr));
|
||||
dst.set_end_ptr(end_ptr);
|
||||
}
|
||||
|
||||
len
|
||||
}
|
||||
|
||||
/// Add `T::max_size()` "red zone" (padding of zeroes) to the end of the vec of
|
||||
/// `bytes`. This allows deserialization to assert that at least `T::max_size()`
|
||||
/// bytes exist at all times.
|
||||
pub fn ensure_red_zone<T: Poke>(bytes: &mut Vec<u8>) {
|
||||
bytes.reserve(T::max_size());
|
||||
unsafe {
|
||||
let end_ptr = bytes.as_end_mut_ptr();
|
||||
end_ptr.write_bytes(0, T::max_size());
|
||||
bytes.set_end_ptr(end_ptr.add(T::max_size()));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn read_verbatim<T>(src: *const u8, dst: *mut T) -> *const u8 {
|
||||
*dst = (src as *const T).read_unaligned();
|
||||
src.add(size_of::<T>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn write_verbatim<T>(src: T, dst: *mut u8) -> *mut u8 {
|
||||
(dst as *mut T).write_unaligned(src);
|
||||
dst.add(size_of::<T>())
|
||||
}
|
||||
|
||||
#[cfg(feature = "extras")]
|
||||
mod euclid;
|
||||
|
||||
/// A trait for values that provide serialization into buffers of bytes.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use peek_poke::Poke;
|
||||
///
|
||||
/// struct Bar {
|
||||
/// a: u32,
|
||||
/// b: u8,
|
||||
/// c: i16,
|
||||
/// }
|
||||
///
|
||||
/// unsafe impl Poke for Bar {
|
||||
/// fn max_size() -> usize {
|
||||
/// <u32>::max_size() + <u8>::max_size() + <i16>::max_size()
|
||||
/// }
|
||||
/// unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
/// let bytes = self.a.poke_into(bytes);
|
||||
/// let bytes = self.b.poke_into(bytes);
|
||||
/// self.c.poke_into(bytes)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `Poke` trait is an `unsafe` trait for the reasons, and implementors must
|
||||
/// ensure that they adhere to these contracts:
|
||||
///
|
||||
/// * `max_size()` query and calculations in general must be correct. Callers
|
||||
/// of this trait are expected to rely on the contract defined on each
|
||||
/// method, and implementors must ensure such contracts remain true.
|
||||
pub unsafe trait Poke {
|
||||
/// Return the maximum number of bytes that the serialized version of `Self`
|
||||
/// will occupy.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Implementors of `Poke` guarantee to not write more than the result of
|
||||
/// calling `max_size()` into the buffer pointed to by `bytes` when
|
||||
/// `poke_into()` is called.
|
||||
fn max_size() -> usize;
|
||||
/// Serialize into the buffer pointed to by `bytes`.
|
||||
///
|
||||
/// Returns a pointer to the next byte after the serialized representation of `Self`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because undefined behavior can result if the
|
||||
/// caller does not ensure all of the following:
|
||||
///
|
||||
/// * `bytes` must denote a valid pointer to a block of memory.
|
||||
///
|
||||
/// * `bytes` must pointer to at least the number of bytes returned by
|
||||
/// `max_size()`.
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8;
|
||||
}
|
||||
|
||||
/// A trait for values that provide deserialization from buffers of bytes.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// use peek_poke::Peek;
|
||||
///
|
||||
/// struct Bar {
|
||||
/// a: u32,
|
||||
/// b: u8,
|
||||
/// c: i16,
|
||||
/// }
|
||||
///
|
||||
/// ...
|
||||
///
|
||||
/// impl Peek for Bar {
|
||||
/// unsafe fn peek_from(&mut self, bytes: *const u8) -> *const u8 {
|
||||
/// let bytes = self.a.peek_from(bytes);
|
||||
/// let bytes = self.b.peek_from(bytes);
|
||||
/// self.c.peek_from(bytes)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `Peek` trait contains unsafe methods for the following reasons, and
|
||||
/// implementors must ensure that they adhere to these contracts:
|
||||
///
|
||||
/// * Callers of this trait are expected to rely on the contract defined on each
|
||||
/// method, and implementors must ensure that `peek_from()` doesn't read more
|
||||
/// bytes from `bytes` than is returned by `Peek::max_size()`.
|
||||
pub trait Peek: Poke {
|
||||
/// Deserialize from the buffer pointed to by `bytes`.
|
||||
///
|
||||
/// Returns a pointer to the next byte after the unconsumed bytes not used
|
||||
/// to deserialize the representation of `Self`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because undefined behavior can result if the
|
||||
/// caller does not ensure all of the following:
|
||||
///
|
||||
/// * `bytes` must denote a valid pointer to a block of memory.
|
||||
///
|
||||
/// * `bytes` must pointer to at least the number of bytes returned by
|
||||
/// `Poke::max_size()`.
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8;
|
||||
}
|
||||
|
||||
macro_rules! impl_poke_for_deref {
|
||||
(<$($desc:tt)+) => {
|
||||
unsafe impl <$($desc)+ {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
<T>::max_size()
|
||||
}
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
(**self).poke_into(bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_poke_for_deref!(<'a, T: Poke> Poke for &'a T);
|
||||
impl_poke_for_deref!(<'a, T: Poke> Poke for &'a mut T);
|
||||
|
||||
macro_rules! impl_for_primitive {
|
||||
($($ty:ty)+) => {
|
||||
$(unsafe impl Poke for $ty {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
size_of::<Self>()
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
write_verbatim(*self, bytes)
|
||||
}
|
||||
}
|
||||
impl Peek for $ty {
|
||||
#[inline(always)]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
read_verbatim(bytes, output)
|
||||
}
|
||||
})+
|
||||
};
|
||||
}
|
||||
|
||||
impl_for_primitive! {
|
||||
i8 i16 i32 i64 isize
|
||||
u8 u16 u32 u64 usize
|
||||
f32 f64
|
||||
}
|
||||
|
||||
unsafe impl Poke for bool {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
u8::max_size()
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
(*self as u8).poke_into(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl Peek for bool {
|
||||
#[inline]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
let mut int_bool = 0u8;
|
||||
let ptr = <u8>::peek_from(bytes, &mut int_bool);
|
||||
*output = int_bool != 0;
|
||||
ptr
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> Poke for PhantomData<T> {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
0
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Peek for PhantomData<T> {
|
||||
#[inline(always)]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
*output = PhantomData;
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Poke> Poke for Option<T> {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
u8::max_size() + T::max_size()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
match self {
|
||||
None => 0u8.poke_into(bytes),
|
||||
Some(ref v) => {
|
||||
let bytes = 1u8.poke_into(bytes);
|
||||
let bytes = v.poke_into(bytes);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default + Peek> Peek for Option<T> {
|
||||
#[inline]
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
let (variant, bytes) = peek_from_default::<u8>(bytes);
|
||||
match variant {
|
||||
0 => {
|
||||
*output = None;
|
||||
bytes
|
||||
}
|
||||
1 => {
|
||||
let (val, bytes) = peek_from_default(bytes);
|
||||
*output = Some(val);
|
||||
bytes
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_for_arrays {
|
||||
($($len:tt)+) => {
|
||||
$(unsafe impl<T: Poke> Poke for [T; $len] {
|
||||
fn max_size() -> usize {
|
||||
$len * T::max_size()
|
||||
}
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
self.iter().fold(bytes, |bytes, e| e.poke_into(bytes))
|
||||
}
|
||||
}
|
||||
impl<T: Peek> Peek for [T; $len] {
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
(&mut *output).iter_mut().fold(bytes, |bytes, e| <T>::peek_from(bytes, e))
|
||||
}
|
||||
})+
|
||||
}
|
||||
}
|
||||
|
||||
impl_for_arrays! {
|
||||
01 02 03 04 05 06 07 08 09 10
|
||||
11 12 13 14 15 16 17 18 19 20
|
||||
21 22 23 24 25 26 27 28 29 30
|
||||
31 32
|
||||
}
|
||||
|
||||
unsafe impl Poke for () {
|
||||
fn max_size() -> usize {
|
||||
0
|
||||
}
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
bytes
|
||||
}
|
||||
}
|
||||
impl Peek for () {
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
*output = ();
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_for_tuple {
|
||||
($($n:tt: $ty:ident),+) => {
|
||||
unsafe impl<$($ty: Poke),+> Poke for ($($ty,)+) {
|
||||
#[inline(always)]
|
||||
fn max_size() -> usize {
|
||||
0 $(+ <$ty>::max_size())+
|
||||
}
|
||||
unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
|
||||
$(let bytes = self.$n.poke_into(bytes);)+
|
||||
bytes
|
||||
}
|
||||
}
|
||||
impl<$($ty: Peek),+> Peek for ($($ty,)+) {
|
||||
unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
|
||||
$(let bytes = $ty::peek_from(bytes, &mut (*output).$n);)+
|
||||
bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_for_tuple!(0: A);
|
||||
impl_for_tuple!(0: A, 1: B);
|
||||
impl_for_tuple!(0: A, 1: B, 2: C);
|
||||
impl_for_tuple!(0: A, 1: B, 2: C, 3: D);
|
||||
impl_for_tuple!(0: A, 1: B, 2: C, 3: D, 4: E);
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub trait AsEndMutPtr<T> {
|
||||
fn as_end_mut_ptr(self) -> *mut T;
|
||||
}
|
||||
|
||||
impl<'a> AsEndMutPtr<u8> for &'a mut [u8] {
|
||||
fn as_end_mut_ptr(self) -> *mut u8 {
|
||||
unsafe { self.as_mut_ptr().add(self.len()) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::vec::Vec;
|
||||
|
||||
pub trait VecExt {
|
||||
type Item;
|
||||
unsafe fn set_end_ptr(&mut self, end: *const Self::Item);
|
||||
}
|
||||
|
||||
impl<T> VecExt for Vec<T> {
|
||||
type Item = T;
|
||||
unsafe fn set_end_ptr(&mut self, end: *const T) {
|
||||
assert!(end as usize >= self.as_ptr() as usize);
|
||||
let new_len = end as usize - self.as_ptr() as usize;
|
||||
assert!(new_len <= self.capacity());
|
||||
self.set_len(new_len);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use peek_poke::{PeekPoke, Poke};
|
||||
use std::{marker::PhantomData, mem::size_of};
|
||||
|
||||
#[test]
|
||||
fn test_numbers() {
|
||||
assert_eq!(u8::max_size(), size_of::<u8>());
|
||||
assert_eq!(u16::max_size(), size_of::<u16>());
|
||||
assert_eq!(u32::max_size(), size_of::<u32>());
|
||||
assert_eq!(u64::max_size(), size_of::<u64>());
|
||||
assert_eq!(usize::max_size(), size_of::<usize>());
|
||||
assert_eq!(i8::max_size(), size_of::<i8>());
|
||||
assert_eq!(i16::max_size(), size_of::<i16>());
|
||||
assert_eq!(i32::max_size(), size_of::<i32>());
|
||||
assert_eq!(i64::max_size(), size_of::<i64>());
|
||||
assert_eq!(isize::max_size(), size_of::<isize>());
|
||||
// floating
|
||||
assert_eq!(f32::max_size(), size_of::<f32>());
|
||||
assert_eq!(f64::max_size(), size_of::<f64>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool() {
|
||||
assert_eq!(bool::max_size(), size_of::<u8>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_option() {
|
||||
assert_eq!(
|
||||
Option::<usize>::max_size(),
|
||||
<u8>::max_size() + <usize>::max_size()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fixed_size_array() {
|
||||
assert_eq!(<[u32; 32]>::max_size(), 32 * size_of::<u32>());
|
||||
assert_eq!(<[u64; 8]>::max_size(), 8 * size_of::<u64>());
|
||||
assert_eq!(<[u8; 19]>::max_size(), 19 * size_of::<u8>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tuple() {
|
||||
assert_eq!(<(isize)>::max_size(), size_of::<isize>());
|
||||
assert_eq!(<(isize, isize, isize)>::max_size(), 3 * size_of::<isize>());
|
||||
assert_eq!(<(isize, ())>::max_size(), size_of::<isize>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_struct() {
|
||||
#[derive(Debug, PeekPoke)]
|
||||
struct Bar {
|
||||
a: u32,
|
||||
b: u32,
|
||||
c: u32,
|
||||
}
|
||||
|
||||
assert_eq!(<Bar>::max_size(), 3 * <u32>::max_size());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enum() {
|
||||
#[derive(Clone, Copy, PeekPoke)]
|
||||
enum TestEnum {
|
||||
NoArg,
|
||||
OneArg(usize),
|
||||
Args(usize, usize),
|
||||
AnotherNoArg,
|
||||
StructLike { x: usize, y: f32 },
|
||||
}
|
||||
assert_eq!(
|
||||
TestEnum::max_size(),
|
||||
<u8>::max_size() + 2 * <usize>::max_size()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enum_cstyle() {
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, PeekPoke)]
|
||||
enum BorderStyle {
|
||||
None = 0,
|
||||
Solid = 1,
|
||||
Double = 2,
|
||||
Dotted = 3,
|
||||
Dashed = 4,
|
||||
Hidden = 5,
|
||||
Groove = 6,
|
||||
Ridge = 7,
|
||||
Inset = 8,
|
||||
Outset = 9,
|
||||
}
|
||||
assert_eq!(BorderStyle::max_size(), <u8>::max_size());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_phantom_data() {
|
||||
struct Bar;
|
||||
#[derive(PeekPoke)]
|
||||
struct Foo {
|
||||
x: u32,
|
||||
y: u32,
|
||||
_marker: PhantomData<Bar>,
|
||||
}
|
||||
assert_eq!(Foo::max_size(), 2 * size_of::<u32>())
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use peek_poke::{Peek, PeekPoke, Poke};
|
||||
use std::{fmt::Debug, marker::PhantomData};
|
||||
|
||||
fn poke_into<V: Peek + Poke>(a: &V) -> Vec<u8> {
|
||||
let mut v = <Vec<u8>>::with_capacity(<V>::max_size());
|
||||
let end_ptr = unsafe { a.poke_into(v.as_mut_ptr()) };
|
||||
let new_size = end_ptr as usize - v.as_ptr() as usize;
|
||||
assert!(new_size <= v.capacity());
|
||||
unsafe {
|
||||
v.set_len(new_size);
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "option_copy"))]
|
||||
fn the_same<V>(a: V)
|
||||
where
|
||||
V: Debug + Default + PartialEq + Peek + Poke,
|
||||
{
|
||||
let v = poke_into(&a);
|
||||
let (b, end_ptr) = unsafe { peek_poke::peek_from_default(v.as_ptr()) };
|
||||
let size = end_ptr as usize - v.as_ptr() as usize;
|
||||
assert_eq!(size, v.len());
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[cfg(feature = "option_copy")]
|
||||
fn the_same<V>(a: V)
|
||||
where
|
||||
V: Copy + Debug + PartialEq + Peek + Poke,
|
||||
{
|
||||
let v = poke_into(&a);
|
||||
let mut b = a;
|
||||
let end_ptr = unsafe { b.peek_from(v.as_ptr()) };
|
||||
let size = end_ptr as usize - v.as_ptr() as usize;
|
||||
assert_eq!(size, v.len());
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numbers() {
|
||||
// unsigned positive
|
||||
the_same(5u8);
|
||||
the_same(5u16);
|
||||
the_same(5u32);
|
||||
the_same(5u64);
|
||||
the_same(5usize);
|
||||
// signed positive
|
||||
the_same(5i8);
|
||||
the_same(5i16);
|
||||
the_same(5i32);
|
||||
the_same(5i64);
|
||||
the_same(5isize);
|
||||
// signed negative
|
||||
the_same(-5i8);
|
||||
the_same(-5i16);
|
||||
the_same(-5i32);
|
||||
the_same(-5i64);
|
||||
the_same(-5isize);
|
||||
// floating
|
||||
the_same(-100f32);
|
||||
the_same(0f32);
|
||||
the_same(5f32);
|
||||
the_same(-100f64);
|
||||
the_same(5f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool() {
|
||||
the_same(true);
|
||||
the_same(false);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "option_copy", feature = "option_default"))]
|
||||
#[test]
|
||||
fn test_option() {
|
||||
the_same(Some(5usize));
|
||||
//the_same(Some("foo bar".to_string()));
|
||||
the_same(None::<usize>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fixed_size_array() {
|
||||
the_same([24u32; 32]);
|
||||
the_same([1u64, 2, 3, 4, 5, 6, 7, 8]);
|
||||
the_same([0u8; 19]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tuple() {
|
||||
the_same((1isize, ));
|
||||
the_same((1isize, 2isize, 3isize));
|
||||
the_same((1isize, ()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_struct() {
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, PeekPoke)]
|
||||
struct Bar {
|
||||
a: u32,
|
||||
b: u32,
|
||||
c: u32,
|
||||
#[cfg(any(feature = "option_copy", feature = "option_default"))]
|
||||
d: Option<u32>,
|
||||
}
|
||||
|
||||
the_same(Bar {
|
||||
a: 2,
|
||||
b: 4,
|
||||
c: 42,
|
||||
#[cfg(any(feature = "option_copy", feature = "option_default"))]
|
||||
d: None,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enum() {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PeekPoke)]
|
||||
enum TestEnum {
|
||||
NoArg,
|
||||
OneArg(usize),
|
||||
Args(usize, usize),
|
||||
AnotherNoArg,
|
||||
StructLike { x: usize, y: f32 },
|
||||
}
|
||||
|
||||
impl Default for TestEnum {
|
||||
fn default() -> Self {
|
||||
TestEnum::NoArg
|
||||
}
|
||||
}
|
||||
|
||||
the_same(TestEnum::NoArg);
|
||||
the_same(TestEnum::OneArg(4));
|
||||
the_same(TestEnum::Args(4, 5));
|
||||
the_same(TestEnum::AnotherNoArg);
|
||||
the_same(TestEnum::StructLike { x: 4, y: 3.14159 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enum_cstyle() {
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PeekPoke)]
|
||||
enum BorderStyle {
|
||||
None = 0,
|
||||
Solid = 1,
|
||||
Double = 2,
|
||||
Dotted = 3,
|
||||
Dashed = 4,
|
||||
Hidden = 5,
|
||||
Groove = 6,
|
||||
Ridge = 7,
|
||||
Inset = 8,
|
||||
Outset = 9,
|
||||
}
|
||||
|
||||
impl Default for BorderStyle {
|
||||
fn default() -> Self {
|
||||
BorderStyle::None
|
||||
}
|
||||
}
|
||||
|
||||
the_same(BorderStyle::None);
|
||||
the_same(BorderStyle::Solid);
|
||||
the_same(BorderStyle::Double);
|
||||
the_same(BorderStyle::Dotted);
|
||||
the_same(BorderStyle::Dashed);
|
||||
the_same(BorderStyle::Hidden);
|
||||
the_same(BorderStyle::Groove);
|
||||
the_same(BorderStyle::Ridge);
|
||||
the_same(BorderStyle::Inset);
|
||||
the_same(BorderStyle::Outset);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_phantom_data() {
|
||||
struct Bar;
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PeekPoke)]
|
||||
struct Foo {
|
||||
x: u32,
|
||||
y: u32,
|
||||
_marker: PhantomData<Bar>,
|
||||
}
|
||||
the_same(Foo {
|
||||
x: 19,
|
||||
y: 42,
|
||||
_marker: PhantomData,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic() {
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PeekPoke)]
|
||||
struct Foo<T> {
|
||||
x: T,
|
||||
y: T,
|
||||
}
|
||||
the_same(Foo { x: 19.0, y: 42.0 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_enum() {
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, PeekPoke)]
|
||||
pub struct PropertyBindingKey<T> {
|
||||
pub id: usize,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PeekPoke)]
|
||||
pub enum PropertyBinding<T> {
|
||||
Value(T),
|
||||
Binding(PropertyBindingKey<T>, T),
|
||||
}
|
||||
|
||||
impl<T: Default> Default for PropertyBinding<T> {
|
||||
fn default() -> Self {
|
||||
PropertyBinding::Value(Default::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "extras", feature = "option_copy"))]
|
||||
mod extra_tests {
|
||||
use super::*;
|
||||
use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, Vector2D};
|
||||
use std::mem::size_of;
|
||||
|
||||
#[test]
|
||||
fn euclid_types() {
|
||||
the_same(Point2D::<f32>::new(1.0, 2.0));
|
||||
assert_eq!(Point2D::<f32>::max_size(), 2 * size_of::<f32>());
|
||||
|
||||
the_same(Rect::<f32>::new(
|
||||
Point2D::<f32>::new(0.0, 0.0),
|
||||
Size2D::<f32>::new(100.0, 80.0),
|
||||
));
|
||||
assert_eq!(Rect::<f32>::max_size(), 4 * size_of::<f32>());
|
||||
|
||||
the_same(SideOffsets2D::<f32>::new(0.0, 10.0, -1.0, -10.0));
|
||||
assert_eq!(SideOffsets2D::<f32>::max_size(), 4 * size_of::<f32>());
|
||||
|
||||
the_same(Transform3D::<f32>::identity());
|
||||
assert_eq!(Transform3D::<f32>::max_size(), 16 * size_of::<f32>());
|
||||
|
||||
the_same(Vector2D::<f32>::new(1.0, 2.0));
|
||||
assert_eq!(Vector2D::<f32>::max_size(), 2 * size_of::<f32>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn webrender_api_types() {
|
||||
type PipelineSourceId = i32;
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PeekPoke)]
|
||||
struct PipelineId(pub PipelineSourceId, pub u32);
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PeekPoke)]
|
||||
struct ClipChainId(pub u64, pub PipelineId);
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PeekPoke)]
|
||||
struct SpatialId(pub usize, pub PipelineId);
|
||||
|
||||
the_same(PipelineId(42, 2));
|
||||
the_same(ClipChainId(19u64, PipelineId(42, 2)));
|
||||
the_same(SpatialId(19usize, PipelineId(42, 2)));
|
||||
}
|
||||
}
|
|
@ -21,13 +21,14 @@ bitflags = "1.0"
|
|||
byteorder = "1.2.1"
|
||||
derive_more = "0.13"
|
||||
ipc-channel = {version = "0.11.0", optional = true}
|
||||
euclid = { version = "0.19.5", features = ["serde"] }
|
||||
euclid = { version = "0.19.9", features = ["serde"] }
|
||||
malloc_size_of_derive = "0.1"
|
||||
serde = { version = "=1.0.88", features = ["rc"] }
|
||||
serde_derive = { version = "=1.0.88", features = ["deserialize_in_place"] }
|
||||
serde_bytes = "0.10"
|
||||
time = "0.1"
|
||||
malloc_size_of = { version = "0.0.1", path = "../wr_malloc_size_of", package = "wr_malloc_size_of" }
|
||||
peek-poke = { version = "0.2", path = "../peek-poke", features = ["extras"] }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation = "0.6"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
extern crate serde_bytes;
|
||||
|
||||
use crate::channel::{self, MsgSender, Payload, PayloadSender, PayloadSenderHelperMethods};
|
||||
use peek_poke::PeekPoke;
|
||||
use std::cell::Cell;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
|
@ -795,11 +796,12 @@ impl Epoch {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, MallocSizeOf, PartialEq, Hash, Ord, PartialOrd, PeekPoke)]
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct IdNamespace(pub u32);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct DocumentId {
|
||||
pub namespace_id: IdNamespace,
|
||||
pub id: u32,
|
||||
|
@ -825,9 +827,15 @@ pub type PipelineSourceId = u32;
|
|||
/// From the point of view of WR, `PipelineId` is completely opaque and generic as long as
|
||||
/// it's clonable, serializable, comparable, and hashable.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct PipelineId(pub PipelineSourceId, pub u32);
|
||||
|
||||
impl Default for PipelineId {
|
||||
fn default() -> Self {
|
||||
PipelineId::dummy()
|
||||
}
|
||||
}
|
||||
|
||||
impl PipelineId {
|
||||
pub fn dummy() -> Self {
|
||||
PipelineId(0, 0)
|
||||
|
@ -1416,7 +1424,7 @@ impl ZoomFactor {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)]
|
||||
pub struct PropertyBindingId {
|
||||
namespace: IdNamespace,
|
||||
uid: u32,
|
||||
|
@ -1434,7 +1442,7 @@ impl PropertyBindingId {
|
|||
/// A unique key that is used for connecting animated property
|
||||
/// values to bindings in the display list.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct PropertyBindingKey<T> {
|
||||
pub id: PropertyBindingId,
|
||||
_phantom: PhantomData<T>,
|
||||
|
@ -1463,12 +1471,18 @@ impl<T> PropertyBindingKey<T> {
|
|||
/// used for the case where the animation is still in-delay phase
|
||||
/// (i.e. the animation doesn't produce any animation values).
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum PropertyBinding<T> {
|
||||
Value(T),
|
||||
Binding(PropertyBindingKey<T>, T),
|
||||
}
|
||||
|
||||
impl<T: Default> Default for PropertyBinding<T> {
|
||||
fn default() -> Self {
|
||||
PropertyBinding::Value(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for PropertyBinding<T> {
|
||||
fn from(value: T) -> PropertyBinding<T> {
|
||||
PropertyBinding::Value(value)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use peek_poke::PeekPoke;
|
||||
use std::cmp;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
|
@ -37,7 +38,7 @@ impl PremultipliedColorF {
|
|||
/// All components must be between 0.0 and 1.0.
|
||||
/// An alpha value of 1.0 is opaque while 0.0 is fully transparent.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ColorF {
|
||||
pub r: f32,
|
||||
pub g: f32,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use euclid::SideOffsets2D;
|
||||
use peek_poke::PeekPoke;
|
||||
use std::ops::Not;
|
||||
// local imports
|
||||
use crate::font;
|
||||
|
@ -34,7 +35,7 @@ pub type ItemTag = (u64, u16);
|
|||
|
||||
/// A grouping of fields a lot of display items need, just to avoid
|
||||
/// repeating these over and over in this file.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct CommonItemProperties {
|
||||
/// Bounds of the display item to clip to. Many items are logically
|
||||
/// infinite, and rely on this clip_rect to define their bounds
|
||||
|
@ -71,7 +72,7 @@ impl CommonItemProperties {
|
|||
/// Note: this is a separate struct from `PrimitiveInfo` because
|
||||
/// it needs indirectional mapping during the DL flattening phase,
|
||||
/// turning into `ScrollNodeAndClipChain`.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct SpaceAndClipInfo {
|
||||
pub spatial_id: SpatialId,
|
||||
pub clip_id: ClipId,
|
||||
|
@ -89,7 +90,7 @@ impl SpaceAndClipInfo {
|
|||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum DisplayItem {
|
||||
// These are the "real content" display items
|
||||
Rectangle(RectangleDisplayItem),
|
||||
|
@ -167,7 +168,7 @@ pub enum DebugDisplayItem {
|
|||
PopAllShadows,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ClipDisplayItem {
|
||||
pub id: ClipId,
|
||||
pub parent_space_and_clip: SpaceAndClipInfo,
|
||||
|
@ -177,7 +178,7 @@ pub struct ClipDisplayItem {
|
|||
|
||||
/// The minimum and maximum allowable offset for a sticky frame in a single dimension.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct StickyOffsetBounds {
|
||||
/// The minimum offset for this frame, typically a negative value, which specifies how
|
||||
/// far in the negative direction the sticky frame can offset its contents in this
|
||||
|
@ -196,7 +197,7 @@ impl StickyOffsetBounds {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct StickyFrameDisplayItem {
|
||||
pub id: SpatialId,
|
||||
pub parent_spatial_id: SpatialId,
|
||||
|
@ -227,13 +228,13 @@ pub struct StickyFrameDisplayItem {
|
|||
pub previously_applied_offset: LayoutVector2D,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum ScrollSensitivity {
|
||||
ScriptAndInputEvents,
|
||||
Script,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ScrollFrameDisplayItem {
|
||||
/// The id of the clip this scroll frame creates
|
||||
pub clip_id: ClipId,
|
||||
|
@ -256,7 +257,7 @@ pub struct ScrollFrameDisplayItem {
|
|||
}
|
||||
|
||||
/// A solid color to draw (may not actually be a rectangle due to complex clips)
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct RectangleDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
pub color: ColorF,
|
||||
|
@ -264,7 +265,7 @@ pub struct RectangleDisplayItem {
|
|||
|
||||
/// Clears all colors from the area, making it possible to cut holes in the window.
|
||||
/// (useful for things like the macos frosted-glass effect).
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ClearRectangleDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
}
|
||||
|
@ -272,12 +273,12 @@ pub struct ClearRectangleDisplayItem {
|
|||
/// A minimal hit-testable item for the parent browser's convenience, and is
|
||||
/// slimmer than a RectangleDisplayItem (no color). The existence of this as a
|
||||
/// distinct item also makes it easier to inspect/debug display items.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct HitTestDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct LineDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
/// We need a separate rect from common.clip_rect to encode cute
|
||||
|
@ -299,14 +300,14 @@ pub struct LineDisplayItem {
|
|||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)]
|
||||
pub enum LineOrientation {
|
||||
Vertical,
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)]
|
||||
pub enum LineStyle {
|
||||
Solid,
|
||||
Dotted,
|
||||
|
@ -314,7 +315,7 @@ pub enum LineStyle {
|
|||
Wavy,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct TextDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
/// The area all the glyphs should be found in. Strictly speaking this isn't
|
||||
|
@ -330,7 +331,7 @@ pub struct TextDisplayItem {
|
|||
pub glyph_options: Option<font::GlyphOptions>,
|
||||
} // IMPLICIT: glyphs: Vec<font::GlyphInstance>
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct NormalBorder {
|
||||
pub left: BorderSide,
|
||||
pub right: BorderSide,
|
||||
|
@ -389,7 +390,7 @@ impl NormalBorder {
|
|||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)]
|
||||
pub enum RepeatMode {
|
||||
Stretch,
|
||||
Repeat,
|
||||
|
@ -397,14 +398,14 @@ pub enum RepeatMode {
|
|||
Space,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum NinePatchBorderSource {
|
||||
Image(ImageKey),
|
||||
Gradient(Gradient),
|
||||
RadialGradient(RadialGradient),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct NinePatchBorder {
|
||||
/// Describes what to use as the 9-patch source image. If this is an image,
|
||||
/// it will be stretched to fill the size given by width x height.
|
||||
|
@ -442,13 +443,13 @@ pub struct NinePatchBorder {
|
|||
pub outset: SideOffsets2D<f32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum BorderDetails {
|
||||
Normal(NormalBorder),
|
||||
NinePatch(NinePatchBorder),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct BorderDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
pub bounds: LayoutRect,
|
||||
|
@ -457,14 +458,14 @@ pub struct BorderDisplayItem {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum BorderRadiusKind {
|
||||
Uniform,
|
||||
NonUniform,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct BorderRadius {
|
||||
pub top_left: LayoutSize,
|
||||
pub top_right: LayoutSize,
|
||||
|
@ -472,15 +473,26 @@ pub struct BorderRadius {
|
|||
pub bottom_right: LayoutSize,
|
||||
}
|
||||
|
||||
impl Default for BorderRadius {
|
||||
fn default() -> Self {
|
||||
BorderRadius {
|
||||
top_left: LayoutSize::zero(),
|
||||
top_right: LayoutSize::zero(),
|
||||
bottom_left: LayoutSize::zero(),
|
||||
bottom_right: LayoutSize::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct BorderSide {
|
||||
pub color: ColorF,
|
||||
pub style: BorderStyle,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Hash, Eq)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Hash, Eq, PeekPoke)]
|
||||
pub enum BorderStyle {
|
||||
None = 0,
|
||||
Solid = 1,
|
||||
|
@ -501,13 +513,13 @@ impl BorderStyle {
|
|||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum BoxShadowClipMode {
|
||||
Outset = 0,
|
||||
Inset = 1,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct BoxShadowDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
pub box_bounds: LayoutRect,
|
||||
|
@ -519,7 +531,7 @@ pub struct BoxShadowDisplayItem {
|
|||
pub clip_mode: BoxShadowClipMode,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct PushShadowDisplayItem {
|
||||
pub space_and_clip: SpaceAndClipInfo,
|
||||
pub shadow: Shadow,
|
||||
|
@ -527,7 +539,7 @@ pub struct PushShadowDisplayItem {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct Shadow {
|
||||
pub offset: LayoutVector2D,
|
||||
pub color: ColorF,
|
||||
|
@ -535,13 +547,13 @@ pub struct Shadow {
|
|||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd, PeekPoke)]
|
||||
pub enum ExtendMode {
|
||||
Clamp,
|
||||
Repeat,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct Gradient {
|
||||
pub start_point: LayoutPoint,
|
||||
pub end_point: LayoutPoint,
|
||||
|
@ -549,7 +561,7 @@ pub struct Gradient {
|
|||
} // IMPLICIT: stops: Vec<GradientStop>
|
||||
|
||||
/// The area
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct GradientDisplayItem {
|
||||
/// NOTE: common.clip_rect is the area the gradient covers
|
||||
pub common: CommonItemProperties,
|
||||
|
@ -565,13 +577,13 @@ pub struct GradientDisplayItem {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct GradientStop {
|
||||
pub offset: f32,
|
||||
pub color: ColorF,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct RadialGradient {
|
||||
pub center: LayoutPoint,
|
||||
pub radius: LayoutSize,
|
||||
|
@ -581,13 +593,13 @@ pub struct RadialGradient {
|
|||
} // IMPLICIT stops: Vec<GradientStop>
|
||||
|
||||
/// Just an abstraction for bundling up a bunch of clips into a "super clip".
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ClipChainItem {
|
||||
pub id: ClipChainId,
|
||||
pub parent: Option<ClipChainId>,
|
||||
} // IMPLICIT clip_ids: Vec<ClipId>
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct RadialGradientDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
/// The area to tile the gradient over (first tile starts at origin of this rect)
|
||||
|
@ -599,14 +611,14 @@ pub struct RadialGradientDisplayItem {
|
|||
pub tile_spacing: LayoutSize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ReferenceFrameDisplayListItem {
|
||||
pub origin: LayoutPoint,
|
||||
pub parent_spatial_id: SpatialId,
|
||||
pub reference_frame: ReferenceFrame,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum ReferenceFrameKind {
|
||||
Transform,
|
||||
Perspective {
|
||||
|
@ -614,7 +626,7 @@ pub enum ReferenceFrameKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ReferenceFrame {
|
||||
pub kind: ReferenceFrameKind,
|
||||
pub transform_style: TransformStyle,
|
||||
|
@ -624,7 +636,7 @@ pub struct ReferenceFrame {
|
|||
pub id: SpatialId,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct PushStackingContextDisplayItem {
|
||||
pub origin: LayoutPoint,
|
||||
pub spatial_id: SpatialId,
|
||||
|
@ -632,7 +644,7 @@ pub struct PushStackingContextDisplayItem {
|
|||
pub stacking_context: StackingContext,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct StackingContext {
|
||||
pub transform_style: TransformStyle,
|
||||
pub mix_blend_mode: MixBlendMode,
|
||||
|
@ -643,7 +655,7 @@ pub struct StackingContext {
|
|||
} // IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData>, filter_primitives: Vec<FilterPrimitive>
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum TransformStyle {
|
||||
Flat = 0,
|
||||
Preserve3D = 1,
|
||||
|
@ -655,7 +667,7 @@ pub enum TransformStyle {
|
|||
/// when we want to cache the output, and performance is
|
||||
/// important. Note that this is a performance hint only,
|
||||
/// which WR may choose to ignore.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
#[repr(u8)]
|
||||
pub enum RasterSpace {
|
||||
// Rasterize in local-space, applying supplied scale to primitives.
|
||||
|
@ -679,7 +691,7 @@ impl RasterSpace {
|
|||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum MixBlendMode {
|
||||
Normal = 0,
|
||||
Multiply = 1,
|
||||
|
@ -701,14 +713,14 @@ pub enum MixBlendMode {
|
|||
|
||||
/// An input to a SVG filter primitive.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum ColorSpace {
|
||||
Srgb,
|
||||
LinearRgb,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum FilterPrimitiveInput {
|
||||
/// The input is the original graphic that the filter is being applied to.
|
||||
Original,
|
||||
|
@ -731,7 +743,7 @@ impl FilterPrimitiveInput {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct BlendPrimitive {
|
||||
pub input1: FilterPrimitiveInput,
|
||||
pub input2: FilterPrimitiveInput,
|
||||
|
@ -739,7 +751,7 @@ pub struct BlendPrimitive {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct FloodPrimitive {
|
||||
pub color: ColorF,
|
||||
}
|
||||
|
@ -754,7 +766,7 @@ impl FloodPrimitive {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct BlurPrimitive {
|
||||
pub input: FilterPrimitiveInput,
|
||||
pub radius: f32,
|
||||
|
@ -767,7 +779,7 @@ impl BlurPrimitive {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct OpacityPrimitive {
|
||||
pub input: FilterPrimitiveInput,
|
||||
pub opacity: f32,
|
||||
|
@ -781,14 +793,14 @@ impl OpacityPrimitive {
|
|||
|
||||
/// cbindgen:derive-eq=false
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ColorMatrixPrimitive {
|
||||
pub input: FilterPrimitiveInput,
|
||||
pub matrix: [f32; 20],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct DropShadowPrimitive {
|
||||
pub input: FilterPrimitiveInput,
|
||||
pub shadow: Shadow,
|
||||
|
@ -801,14 +813,14 @@ impl DropShadowPrimitive {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ComponentTransferPrimitive {
|
||||
pub input: FilterPrimitiveInput,
|
||||
// Component transfer data is stored in FilterData.
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct IdentityPrimitive {
|
||||
pub input: FilterPrimitiveInput,
|
||||
}
|
||||
|
@ -816,7 +828,7 @@ pub struct IdentityPrimitive {
|
|||
/// See: https://github.com/eqrion/cbindgen/issues/9
|
||||
/// cbindgen:derive-eq=false
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum FilterPrimitiveKind {
|
||||
Identity(IdentityPrimitive),
|
||||
Blend(BlendPrimitive),
|
||||
|
@ -830,6 +842,12 @@ pub enum FilterPrimitiveKind {
|
|||
ComponentTransfer(ComponentTransferPrimitive),
|
||||
}
|
||||
|
||||
impl Default for FilterPrimitiveKind {
|
||||
fn default() -> Self {
|
||||
FilterPrimitiveKind::Identity(IdentityPrimitive::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterPrimitiveKind {
|
||||
pub fn sanitize(&mut self) {
|
||||
match self {
|
||||
|
@ -852,7 +870,7 @@ impl FilterPrimitiveKind {
|
|||
/// See: https://github.com/eqrion/cbindgen/issues/9
|
||||
/// cbindgen:derive-eq=false
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct FilterPrimitive {
|
||||
pub kind: FilterPrimitiveKind,
|
||||
pub color_space: ColorSpace,
|
||||
|
@ -866,7 +884,7 @@ impl FilterPrimitive {
|
|||
|
||||
/// CSS filter.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, PeekPoke)]
|
||||
pub enum FilterOp {
|
||||
/// Filter that does no transformation of the colors, needed for
|
||||
/// debug purposes only.
|
||||
|
@ -889,7 +907,7 @@ pub enum FilterOp {
|
|||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, PeekPoke)]
|
||||
pub enum ComponentTransferFuncType {
|
||||
Identity = 0,
|
||||
Table = 1,
|
||||
|
@ -985,7 +1003,7 @@ impl FilterData {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct IframeDisplayItem {
|
||||
pub bounds: LayoutRect,
|
||||
pub clip_rect: LayoutRect,
|
||||
|
@ -996,7 +1014,7 @@ pub struct IframeDisplayItem {
|
|||
|
||||
/// This describes an image or, more generally, a background-image and its tiling.
|
||||
/// (A background-image repeats in a grid to fill the specified area).
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ImageDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
/// The area to tile the image over (first tile starts at origin of this rect)
|
||||
|
@ -1015,20 +1033,20 @@ pub struct ImageDisplayItem {
|
|||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum ImageRendering {
|
||||
Auto = 0,
|
||||
CrispEdges = 1,
|
||||
Pixelated = 2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum AlphaType {
|
||||
Alpha = 0,
|
||||
PremultipliedAlpha = 1,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct YuvImageDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
pub bounds: LayoutRect,
|
||||
|
@ -1039,14 +1057,14 @@ pub struct YuvImageDisplayItem {
|
|||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum YuvColorSpace {
|
||||
Rec601 = 0,
|
||||
Rec709 = 1,
|
||||
Rec2020 = 2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum YuvData {
|
||||
NV12(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel)
|
||||
PlanarYCbCr(ImageKey, ImageKey, ImageKey), // (Y channel, Cb channel, Cr Channel)
|
||||
|
@ -1063,7 +1081,7 @@ impl YuvData {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum YuvFormat {
|
||||
NV12 = 0,
|
||||
PlanarYCbCr = 1,
|
||||
|
@ -1081,7 +1099,7 @@ impl YuvFormat {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ImageMask {
|
||||
pub image: ImageKey,
|
||||
pub rect: LayoutRect,
|
||||
|
@ -1100,7 +1118,7 @@ impl ImageMask {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
#[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)]
|
||||
pub enum ClipMode {
|
||||
Clip, // Pixels inside the region are visible.
|
||||
ClipOut, // Pixels outside the region are visible.
|
||||
|
@ -1118,7 +1136,7 @@ impl Not for ClipMode {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ComplexClipRegion {
|
||||
/// The boundaries of the rectangle.
|
||||
pub rect: LayoutRect,
|
||||
|
@ -1209,11 +1227,11 @@ impl ComplexClipRegion {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ClipChainId(pub u64, pub PipelineId);
|
||||
|
||||
/// A reference to a clipping node defining how an item is clipped.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum ClipId {
|
||||
Clip(usize, PipelineId),
|
||||
ClipChain(ClipChainId),
|
||||
|
@ -1256,7 +1274,7 @@ impl ClipId {
|
|||
}
|
||||
|
||||
/// A reference to a spatial node defining item positioning.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct SpatialId(pub usize, PipelineId);
|
||||
|
||||
const ROOT_REFERENCE_FRAME_SPATIAL_ID: usize = 0;
|
||||
|
@ -1295,7 +1313,7 @@ impl SpatialId {
|
|||
///
|
||||
/// When setting display lists with the `preserve_frame_state` this id is used to preserve scroll
|
||||
/// offsets between different sets of ClipScrollNodes which are ScrollFrames.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
|
||||
#[repr(C)]
|
||||
pub struct ExternalScrollId(pub u64, pub PipelineId);
|
||||
|
||||
|
@ -1341,3 +1359,44 @@ impl DisplayItem {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_default_for_enums {
|
||||
($($enum:ident => $init:expr ),+) => {
|
||||
$(impl Default for $enum {
|
||||
#[allow(unused_imports)]
|
||||
fn default() -> Self {
|
||||
use $enum::*;
|
||||
$init
|
||||
}
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
impl_default_for_enums! {
|
||||
DisplayItem => PopStackingContext,
|
||||
ScrollSensitivity => ScriptAndInputEvents,
|
||||
LineOrientation => Vertical,
|
||||
LineStyle => Solid,
|
||||
RepeatMode => Stretch,
|
||||
NinePatchBorderSource => Image(ImageKey::default()),
|
||||
BorderDetails => Normal(NormalBorder::default()),
|
||||
BorderRadiusKind => Uniform,
|
||||
BorderStyle => None,
|
||||
BoxShadowClipMode => Outset,
|
||||
ExtendMode => Clamp,
|
||||
FilterOp => Identity,
|
||||
ComponentTransferFuncType => Identity,
|
||||
ClipMode => Clip,
|
||||
ClipId => ClipId::invalid(),
|
||||
ReferenceFrameKind => Transform,
|
||||
TransformStyle => Flat,
|
||||
RasterSpace => Local(f32::default()),
|
||||
MixBlendMode => Normal,
|
||||
ImageRendering => Auto,
|
||||
AlphaType => Alpha,
|
||||
YuvColorSpace => Rec601,
|
||||
YuvData => NV12(ImageKey::default(), ImageKey::default()),
|
||||
YuvFormat => NV12,
|
||||
FilterPrimitiveInput => Original,
|
||||
ColorSpace => Srgb
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
use bincode;
|
||||
use euclid::SideOffsets2D;
|
||||
use peek_poke::{ensure_red_zone, peek_from_slice, poke_extend_vec};
|
||||
use peek_poke::{poke_inplace_slice, poke_into_vec, Poke};
|
||||
#[cfg(feature = "deserialize")]
|
||||
use serde::de::Deserializer;
|
||||
#[cfg(feature = "serialize")]
|
||||
|
@ -67,18 +69,15 @@ impl<'a, T> ItemRange<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T> ItemRange<'a, T>
|
||||
where
|
||||
for<'de> T: Deserialize<'de>,
|
||||
{
|
||||
impl<'a, T: Default> ItemRange<'a, T> {
|
||||
pub fn iter(&self) -> AuxIter<'a, T> {
|
||||
AuxIter::new(self.bytes)
|
||||
AuxIter::new(T::default(), self.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for ItemRange<'a, T>
|
||||
where
|
||||
for<'de> T: Deserialize<'de>,
|
||||
T: Copy + Default + peek_poke::Peek,
|
||||
{
|
||||
type Item = T;
|
||||
type IntoIter = AuxIter<'a, T>;
|
||||
|
@ -176,7 +175,7 @@ impl DebugStats {
|
|||
|
||||
/// Logs the stats for the given serialized slice
|
||||
#[cfg(feature = "display_list_stats")]
|
||||
fn log_slice<T: for<'de> Deserialize<'de>>(
|
||||
fn log_slice<T: Peek>(
|
||||
&mut self,
|
||||
slice_name: &'static str,
|
||||
range: &ItemRange<T>,
|
||||
|
@ -186,7 +185,7 @@ impl DebugStats {
|
|||
// processed, and the `range` has everything we need.
|
||||
self.last_addr = range.bytes.as_ptr() as usize + range.bytes.len();
|
||||
|
||||
self._update_entry(slice_name, range.iter().size_hint().0, range.bytes.len());
|
||||
self._update_entry(slice_name, range.iter().len(), range.bytes.len());
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "display_list_stats"))]
|
||||
|
@ -217,9 +216,10 @@ enum Peek {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct AuxIter<'a, T> {
|
||||
item: T,
|
||||
data: &'a [u8],
|
||||
size: usize,
|
||||
_boo: PhantomData<T>,
|
||||
// _boo: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl BuiltDisplayListDescriptor {}
|
||||
|
@ -268,11 +268,10 @@ impl BuiltDisplayList {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the byte-range the slice occupied, and the number of elements
|
||||
/// in the slice.
|
||||
fn skip_slice<'a, T: for<'de> Deserialize<'de>>(mut data: &mut &'a [u8]) -> ItemRange<'a, T> {
|
||||
let skip_offset: usize = bincode::deserialize_from(&mut data).expect("MEH: malicious input?");
|
||||
|
||||
/// Returns the byte-range the slice occupied.
|
||||
fn skip_slice<'a, T: peek_poke::Peek>(data: &mut &'a [u8]) -> ItemRange<'a, T> {
|
||||
let mut skip_offset = 0usize;
|
||||
*data = peek_from_slice(data, &mut skip_offset);
|
||||
let (skip, rest) = data.split_at(skip_offset);
|
||||
|
||||
// Adjust data pointer to skip read values
|
||||
|
@ -357,16 +356,14 @@ impl<'a> BuiltDisplayListIter<'a> {
|
|||
pub fn next_raw<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> {
|
||||
use crate::DisplayItem::*;
|
||||
|
||||
if self.data.is_empty() {
|
||||
// A "red zone" of DisplayItem::max_size() bytes has been added to the
|
||||
// end of the serialized display list. If this amount, or less, is
|
||||
// remaining then we've reached the end of the display list.
|
||||
if self.data.len() <= di::DisplayItem::max_size() {
|
||||
return None;
|
||||
}
|
||||
|
||||
{
|
||||
let reader = bincode::IoReader::new(UnsafeReader::new(&mut self.data));
|
||||
bincode::deserialize_in_place(reader, &mut self.cur_item)
|
||||
.expect("MEH: malicious process?");
|
||||
}
|
||||
|
||||
self.data = peek_from_slice(self.data, &mut self.cur_item);
|
||||
self.log_item_stats();
|
||||
|
||||
match self.cur_item {
|
||||
|
@ -527,34 +524,32 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, T: Deserialize<'de>> AuxIter<'a, T> {
|
||||
pub fn new(mut data: &'a [u8]) -> Self {
|
||||
let size: usize = if data.is_empty() {
|
||||
0 // Accept empty ItemRanges pointing anywhere
|
||||
} else {
|
||||
bincode::deserialize_from(&mut UnsafeReader::new(&mut data)).expect("MEH: malicious input?")
|
||||
impl<'a, T> AuxIter<'a, T> {
|
||||
pub fn new(item: T, mut data: &'a [u8]) -> Self {
|
||||
let mut size = 0usize;
|
||||
if !data.is_empty() {
|
||||
data = peek_from_slice(data, &mut size);
|
||||
};
|
||||
|
||||
AuxIter {
|
||||
item,
|
||||
data,
|
||||
size,
|
||||
_boo: PhantomData,
|
||||
// _boo: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: for<'de> Deserialize<'de>> Iterator for AuxIter<'a, T> {
|
||||
impl<'a, T: Copy + peek_poke::Peek> Iterator for AuxIter<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.size == 0 {
|
||||
None
|
||||
} else {
|
||||
self.size -= 1;
|
||||
Some(
|
||||
bincode::deserialize_from(&mut UnsafeReader::new(&mut self.data))
|
||||
.expect("MEH: malicious input?"),
|
||||
)
|
||||
self.data = peek_from_slice(self.data, &mut self.item);
|
||||
Some(self.item)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,7 +558,7 @@ impl<'a, T: for<'de> Deserialize<'de>> Iterator for AuxIter<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: for<'de> Deserialize<'de>> ::std::iter::ExactSizeIterator for AuxIter<'a, T> {}
|
||||
impl<'a, T: Copy + peek_poke::Peek> ::std::iter::ExactSizeIterator for AuxIter<'a, T> {}
|
||||
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
|
@ -740,7 +735,7 @@ impl<'de> Deserialize<'de> for BuiltDisplayList {
|
|||
Debug::PopReferenceFrame => Real::PopReferenceFrame,
|
||||
Debug::PopAllShadows => Real::PopAllShadows,
|
||||
};
|
||||
serialize_fast(&mut data, &item);
|
||||
poke_into_vec(&item, &mut data);
|
||||
// the aux data is serialized after the item, hence the temporary
|
||||
data.extend(temp.drain(..));
|
||||
}
|
||||
|
@ -834,78 +829,6 @@ impl<'a> Write for SizeCounter {
|
|||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
/// Serializes a value assuming the Serialize impl has a stable size across two
|
||||
/// invocations.
|
||||
///
|
||||
/// If this assumption is incorrect, the result will be Undefined Behaviour. This
|
||||
/// assumption should hold for all derived Serialize impls, which is all we currently
|
||||
/// use.
|
||||
fn serialize_fast<T: Serialize>(vec: &mut Vec<u8>, e: T) {
|
||||
// manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason
|
||||
let mut size = SizeCounter(0);
|
||||
bincode::serialize_into(&mut size, &e).unwrap();
|
||||
vec.reserve(size.0);
|
||||
|
||||
let old_len = vec.len();
|
||||
let ptr = unsafe { vec.as_mut_ptr().add(old_len) };
|
||||
let mut w = UnsafeVecWriter(ptr);
|
||||
bincode::serialize_into(&mut w, &e).unwrap();
|
||||
|
||||
// fix up the length
|
||||
unsafe { vec.set_len(old_len + size.0); }
|
||||
|
||||
// make sure we wrote the right amount
|
||||
debug_assert_eq!(((w.0 as usize) - (vec.as_ptr() as usize)), vec.len());
|
||||
}
|
||||
|
||||
/// Serializes an iterator, assuming:
|
||||
///
|
||||
/// * The Clone impl is trivial (e.g. we're just memcopying a slice iterator)
|
||||
/// * The ExactSizeIterator impl is stable and correct across a Clone
|
||||
/// * The Serialize impl has a stable size across two invocations
|
||||
///
|
||||
/// If the first is incorrect, WebRender will be very slow. If the other two are
|
||||
/// incorrect, the result will be Undefined Behaviour! The ExactSizeIterator
|
||||
/// bound would ideally be replaced with a TrustedLen bound to protect us a bit
|
||||
/// better, but that trait isn't stable (and won't be for a good while, if ever).
|
||||
///
|
||||
/// Debug asserts are included that should catch all Undefined Behaviour, but
|
||||
/// we can't afford to include these in release builds.
|
||||
fn serialize_iter_fast<I>(vec: &mut Vec<u8>, iter: I) -> usize
|
||||
where I: ExactSizeIterator + Clone,
|
||||
I::Item: Serialize,
|
||||
{
|
||||
// manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason
|
||||
let mut size = SizeCounter(0);
|
||||
let mut count1 = 0;
|
||||
|
||||
for e in iter.clone() {
|
||||
bincode::serialize_into(&mut size, &e).unwrap();
|
||||
count1 += 1;
|
||||
}
|
||||
|
||||
vec.reserve(size.0);
|
||||
|
||||
let old_len = vec.len();
|
||||
let ptr = unsafe { vec.as_mut_ptr().add(old_len) };
|
||||
let mut w = UnsafeVecWriter(ptr);
|
||||
let mut count2 = 0;
|
||||
|
||||
for e in iter {
|
||||
bincode::serialize_into(&mut w, &e).unwrap();
|
||||
count2 += 1;
|
||||
}
|
||||
|
||||
// fix up the length
|
||||
unsafe { vec.set_len(old_len + size.0); }
|
||||
|
||||
// make sure we wrote the right amount
|
||||
debug_assert_eq!(((w.0 as usize) - (vec.as_ptr() as usize)), vec.len());
|
||||
debug_assert_eq!(count1, count2);
|
||||
|
||||
count1
|
||||
}
|
||||
|
||||
// This uses a (start, end) representation instead of (start, len) so that
|
||||
// only need to update a single field as we read through it. This
|
||||
// makes it easier for llvm to understand what's going on. (https://github.com/rust-lang/rust/issues/45068)
|
||||
|
@ -1108,38 +1031,39 @@ impl DisplayListBuilder {
|
|||
/// result in WebRender panicking or behaving in unexpected ways.
|
||||
#[inline]
|
||||
pub fn push_item(&mut self, item: &di::DisplayItem) {
|
||||
serialize_fast(&mut self.data, item);
|
||||
poke_into_vec(item, &mut self.data);
|
||||
}
|
||||
|
||||
fn push_iter_impl<I>(data: &mut Vec<u8>, iter_source: I)
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::IntoIter: ExactSizeIterator + Clone,
|
||||
I::Item: Serialize,
|
||||
I::IntoIter: ExactSizeIterator,
|
||||
I::Item: Poke,
|
||||
{
|
||||
let iter = iter_source.into_iter();
|
||||
let len = iter.len();
|
||||
// Format:
|
||||
// payload_byte_size: usize, item_count: usize, [I; item_count]
|
||||
|
||||
// We write a dummy value so there's room for later
|
||||
// Track the the location of where to write byte size with offsets
|
||||
// instead of pointers because data may be moved in memory during
|
||||
// `serialize_iter_fast`.
|
||||
let byte_size_offset = data.len();
|
||||
serialize_fast(data, &0usize);
|
||||
let payload_offset = data.len();
|
||||
serialize_fast(data, &len);
|
||||
let count = serialize_iter_fast(data, iter);
|
||||
|
||||
// We write a dummy value so there's room for later
|
||||
poke_into_vec(&0usize, data);
|
||||
poke_into_vec(&len, data);
|
||||
let count = poke_extend_vec(iter, data);
|
||||
debug_assert_eq!(len, count);
|
||||
|
||||
// Add red zone
|
||||
ensure_red_zone::<I::Item>(data);
|
||||
|
||||
// Now write the actual byte_size
|
||||
let final_offset = data.len();
|
||||
let byte_size = final_offset - payload_offset;
|
||||
|
||||
// Note we don't use serialize_fast because we don't want to change the Vec's len
|
||||
bincode::serialize_into(
|
||||
&mut &mut data[byte_size_offset..],
|
||||
&byte_size,
|
||||
).unwrap();
|
||||
|
||||
debug_assert_eq!(len, count);
|
||||
debug_assert!(final_offset >= (byte_size_offset + mem::size_of::<usize>()));
|
||||
let byte_size = final_offset - byte_size_offset - mem::size_of::<usize>();
|
||||
poke_inplace_slice(&byte_size, &mut data[byte_size_offset..]);
|
||||
}
|
||||
|
||||
/// Push items from an iterator to the display list.
|
||||
|
@ -1149,8 +1073,8 @@ impl DisplayListBuilder {
|
|||
pub fn push_iter<I>(&mut self, iter: I)
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::IntoIter: ExactSizeIterator + Clone,
|
||||
I::Item: Serialize,
|
||||
I::IntoIter: ExactSizeIterator,
|
||||
I::Item: Poke,
|
||||
{
|
||||
Self::push_iter_impl(&mut self.data, iter);
|
||||
}
|
||||
|
@ -1684,9 +1608,14 @@ impl DisplayListBuilder {
|
|||
self.push_item(&di::DisplayItem::PopAllShadows);
|
||||
}
|
||||
|
||||
pub fn finalize(self) -> (PipelineId, LayoutSize, BuiltDisplayList) {
|
||||
pub fn finalize(mut self) -> (PipelineId, LayoutSize, BuiltDisplayList) {
|
||||
assert!(self.save_state.is_none(), "Finalized DisplayListBuilder with a pending save");
|
||||
|
||||
// Add `DisplayItem::max_size` zone of zeroes to the end of display list
|
||||
// so there is at least this amount available in the display list during
|
||||
// serialization.
|
||||
ensure_red_zone::<di::DisplayItem>(&mut self.data);
|
||||
|
||||
let end_time = precise_time_ns();
|
||||
|
||||
(
|
||||
|
|
|
@ -7,6 +7,7 @@ use app_units::Au;
|
|||
use core_foundation::string::CFString;
|
||||
#[cfg(target_os = "macos")]
|
||||
use core_graphics::font::CGFont;
|
||||
use peek_poke::PeekPoke;
|
||||
#[cfg(target_os = "macos")]
|
||||
use serde::de::{self, Deserialize, Deserializer};
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -97,13 +98,19 @@ pub enum FontTemplate {
|
|||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd, PeekPoke)]
|
||||
pub enum FontRenderMode {
|
||||
Mono = 0,
|
||||
Alpha,
|
||||
Subpixel,
|
||||
}
|
||||
|
||||
impl Default for FontRenderMode {
|
||||
fn default() -> Self {
|
||||
FontRenderMode::Mono
|
||||
}
|
||||
}
|
||||
|
||||
impl FontRenderMode {
|
||||
// Combine two font render modes such that the lesser amount of AA limits the AA of the result.
|
||||
pub fn limit_by(self, other: FontRenderMode) -> FontRenderMode {
|
||||
|
@ -145,7 +152,7 @@ impl Hash for FontVariation {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, PeekPoke)]
|
||||
pub struct GlyphOptions {
|
||||
pub render_mode: FontRenderMode,
|
||||
pub flags: FontInstanceFlags,
|
||||
|
@ -162,7 +169,7 @@ impl Default for GlyphOptions {
|
|||
|
||||
bitflags! {
|
||||
#[repr(C)]
|
||||
#[derive(Deserialize, MallocSizeOf, Serialize)]
|
||||
#[derive(Deserialize, MallocSizeOf, Serialize, PeekPoke)]
|
||||
pub struct FontInstanceFlags: u32 {
|
||||
// Common flags
|
||||
const SYNTHETIC_BOLD = 1 << 1;
|
||||
|
@ -348,7 +355,8 @@ impl Default for FontInstancePlatformOptions {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Ord, PartialOrd, MallocSizeOf)]
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Ord, PartialOrd, MallocSizeOf, PeekPoke)]
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct FontInstanceKey(pub IdNamespace, pub u32);
|
||||
|
||||
impl FontInstanceKey {
|
||||
|
@ -373,12 +381,21 @@ pub struct FontInstanceData {
|
|||
pub type GlyphIndex = u32;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct GlyphInstance {
|
||||
pub index: GlyphIndex,
|
||||
pub point: LayoutPoint,
|
||||
}
|
||||
|
||||
impl Default for GlyphInstance {
|
||||
fn default() -> Self {
|
||||
GlyphInstance {
|
||||
index: 0,
|
||||
point: LayoutPoint::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for GlyphInstance {}
|
||||
|
||||
impl Hash for GlyphInstance {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#![deny(missing_docs)]
|
||||
|
||||
use euclid::{size2, TypedRect, num::Zero};
|
||||
use peek_poke::PeekPoke;
|
||||
use std::ops::{Add, Sub};
|
||||
use std::sync::Arc;
|
||||
// local imports
|
||||
|
@ -16,9 +17,15 @@ use crate::units::*;
|
|||
/// This is used as a handle to reference images, and is used as the
|
||||
/// hash map key for the actual image storage in the `ResourceCache`.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ImageKey(pub IdNamespace, pub u32);
|
||||
|
||||
impl Default for ImageKey {
|
||||
fn default() -> Self {
|
||||
ImageKey::DUMMY
|
||||
}
|
||||
}
|
||||
|
||||
impl ImageKey {
|
||||
/// Placeholder Image key, used to represent None.
|
||||
pub const DUMMY: Self = ImageKey(IdNamespace(0), 0);
|
||||
|
@ -142,7 +149,7 @@ impl ImageFormat {
|
|||
|
||||
/// Specifies the color depth of an image. Currently only used for YUV images.
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum ColorDepth {
|
||||
/// 8 bits image (most common)
|
||||
Color8,
|
||||
|
@ -154,6 +161,12 @@ pub enum ColorDepth {
|
|||
Color16,
|
||||
}
|
||||
|
||||
impl Default for ColorDepth {
|
||||
fn default() -> Self {
|
||||
ColorDepth::Color8
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorDepth {
|
||||
/// Return the numerical bit depth value for the type.
|
||||
pub fn bit_depth(self) -> u32 {
|
||||
|
|
|
@ -38,6 +38,7 @@ extern crate serde_derive;
|
|||
extern crate time;
|
||||
|
||||
extern crate malloc_size_of;
|
||||
extern crate peek_poke;
|
||||
|
||||
mod api;
|
||||
pub mod channel;
|
||||
|
|
|
@ -16,6 +16,7 @@ pub use app_units::Au;
|
|||
use euclid::{Length, TypedRect, TypedScale, TypedSize2D, TypedTransform3D, TypedTranslation2D};
|
||||
use euclid::{TypedPoint2D, TypedPoint3D, TypedVector2D, TypedVector3D, TypedSideOffsets2D};
|
||||
use euclid::HomogeneousVector;
|
||||
use peek_poke::PeekPoke;
|
||||
// local imports
|
||||
use crate::image::DirtyRect;
|
||||
|
||||
|
@ -77,7 +78,7 @@ pub type RasterVector2D = TypedVector2D<f32, RasterPixel>;
|
|||
pub type RasterVector3D = TypedVector3D<f32, RasterPixel>;
|
||||
|
||||
/// Geometry in a stacking context's local coordinate space (logical pixels).
|
||||
#[derive(Hash, Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
#[derive(Hash, Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Ord, PartialOrd, Deserialize, Serialize, PeekPoke)]
|
||||
pub struct LayoutPixel;
|
||||
|
||||
pub type LayoutRect = TypedRect<f32, LayoutPixel>;
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"4c50cb6cf03b2ab58cf9c017fdeee3f3d918b6143adeb529910f329bb07e7fd3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6594377e8f6c20f88f628520d8de9b9a59c5892a0ee9a6ccd13c8400c1499911","src/homogen.rs":"7b02aa671fffcb554557ad790f598bd5d7440dc1aa4a6d1c5a97d8bc3c8f64d6","src/length.rs":"3171315822707728b1bfbdd04a4190ffb7206b4bfc59e9dd072bb2caa05ff292","src/lib.rs":"e8b1317127ec281fd42318f2c470558c2ecbb2e1459cebd4f9c63a2af807eb3d","src/macros.rs":"3b475e84d00cceee6c7e96e9f2c97ba15d8dc7f4094efb82c5ed10bd60d86a64","src/num.rs":"4439479fad5729073e0bfe0b96b547672a237430d48e564519759b9550baa033","src/point.rs":"689a8348428d12f6c5262965c505395bde37b4b1776369d93e93d73406d5344b","src/rect.rs":"ae16bb9ccb95cf329439d0ea4eb4c3821c4cd769cce4a544904b65d7e4af04b7","src/rotation.rs":"3d765a8e8e8c7181cc10d39be617779a8676d2611b408c69c841c3a10ce78a47","src/scale.rs":"fc07bcf47f3a1215023c830059f0d270e570cbd37fe8c367ef4a47b191f4ae3e","src/side_offsets.rs":"b79d43cca4c2e9fac7482a95661f72cb3ed51008f1d3e0c3f4fe608c68ef3658","src/size.rs":"49088bf3bf0e1ce740c1fe92761c18a43a6287d1d81a945bc92b21af63ef3416","src/transform2d.rs":"641acc1c9de9368bdbe0bb64b5ba4c1069ebeda6d6ad31463c81bdf85d678043","src/transform3d.rs":"c47dda0759629c1a836861fabf65e889001cf2d5ab59258544c1c04167cd7a67","src/translation.rs":"9787de1bccdd402774ba9a5bc55ec6d4b2ee36e0a146baecee417ee9cc753db5","src/trig.rs":"97a263c4f178b0332501659ca8143f9f637a0755aca189dd31ac551bcd4cb73c","src/vector.rs":"d57493649da9d8a728dcba49bb80c579a4d2bf6f3557dd4b4c770cfcef6ee395"},"package":"d1a7698bdda3d7444a79d33bdc96e8b518d44ea3ff101d8492a6ca1207b886ea"}
|
||||
{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"6ed8512d0e0c349a53eddd15a806e67e84359c1071d7d4a404f513cca091d5f5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6594377e8f6c20f88f628520d8de9b9a59c5892a0ee9a6ccd13c8400c1499911","src/approxord.rs":"087e0a8d24b8a9bed4c1cc571eec5e50cc7afa184c6ac4961c7409a69456ec7b","src/box2d.rs":"5e2d634cf2181fd9f556a600d4339cb6a098341ac71f72e0bc7521b3b3fb2f19","src/box3d.rs":"8d87e7e487d0772462cc2c6033bcd05f4fee44127c4aa0a4d72407ac6a02e03b","src/homogen.rs":"7b02aa671fffcb554557ad790f598bd5d7440dc1aa4a6d1c5a97d8bc3c8f64d6","src/length.rs":"3171315822707728b1bfbdd04a4190ffb7206b4bfc59e9dd072bb2caa05ff292","src/lib.rs":"e8bbae14e1b284fba3529af44396e488cbc48f8b3d20ddb26da5919d9c02601b","src/macros.rs":"3b475e84d00cceee6c7e96e9f2c97ba15d8dc7f4094efb82c5ed10bd60d86a64","src/num.rs":"4439479fad5729073e0bfe0b96b547672a237430d48e564519759b9550baa033","src/point.rs":"b51cf9b7713d9a48452d833cfbc97bb95e0c2202c4f77cadd02633ce80a600df","src/rect.rs":"2e4036f3f7e2ca62e6f9a52787ca9b9765b401a11cf1e70dff6c81142bdd91ed","src/rigid.rs":"e50a5df42add328ed5164e1954592406ce6d8f564beb4ca375c5cca920e93fbc","src/rotation.rs":"3d1a934a7c59bd7ca8501d17d463d5af41fb529c5aa8fe8c3bb8a2b236d4abc0","src/scale.rs":"fc07bcf47f3a1215023c830059f0d270e570cbd37fe8c367ef4a47b191f4ae3e","src/side_offsets.rs":"d9b1463672e1204bf8e7dd6fe0f7601eb75b6690ec6eb18debcee07f5ca92ee3","src/size.rs":"c4e38966c280ab5b4963961eebdbb12e0f448aea624cbe760b02ca2221a004e5","src/transform2d.rs":"7657d447993dc820e404ea9fbde6cb2900d874d4f5c735e85c6225c9f3b4110d","src/transform3d.rs":"af3d909ee103d02fec5f59599055cc3cee5217975b030e0089e1f1d99ad5139e","src/translation.rs":"b21d1d81a34b80d3285d42f33e8039fdb787749f017d2a7a2295d036c2f50548","src/trig.rs":"97a263c4f178b0332501659ca8143f9f637a0755aca189dd31ac551bcd4cb73c","src/vector.rs":"dcd0904757ed0e7d12da1c612746da3e32c56e2248ec13041d1f3786811af51c"},"package":"596b99621b9477e7a5f94d2d8dd13a9c5c302ac358b822c67a42b6f1054450e1"}
|
|
@ -3,7 +3,7 @@
|
|||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
|
@ -12,7 +12,7 @@
|
|||
|
||||
[package]
|
||||
name = "euclid"
|
||||
version = "0.19.5"
|
||||
version = "0.19.9"
|
||||
authors = ["The Servo Project Developers"]
|
||||
description = "Geometry primitives"
|
||||
documentation = "https://docs.rs/euclid/"
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/// Utilities for testing approximate ordering - especially true for
|
||||
/// floating point types, where NaN's cannot be ordered.
|
||||
pub fn min<T: PartialOrd>(x: T, y: T) -> T {
|
||||
if x <= y {
|
||||
x
|
||||
} else {
|
||||
y
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max<T: PartialOrd>(x: T, y: T) -> T {
|
||||
if x >= y {
|
||||
x
|
||||
} else {
|
||||
y
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_min() {
|
||||
assert!(min(0u32, 1u32) == 0u32);
|
||||
assert!(min(-1.0f32, 0.0f32) == -1.0f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max() {
|
||||
assert!(max(0u32, 1u32) == 1u32);
|
||||
assert!(max(-1.0f32, 0.0f32) == 0.0f32);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,793 @@
|
|||
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::UnknownUnit;
|
||||
use scale::TypedScale;
|
||||
use num::*;
|
||||
use rect::TypedRect;
|
||||
use point::{point2, TypedPoint2D};
|
||||
use vector::{vec2, TypedVector2D};
|
||||
use side_offsets::TypedSideOffsets2D;
|
||||
use size::TypedSize2D;
|
||||
use approxord::{min, max};
|
||||
|
||||
use num_traits::NumCast;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use core::borrow::Borrow;
|
||||
use core::cmp::PartialOrd;
|
||||
use core::fmt;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::ops::{Add, Div, Mul, Sub};
|
||||
|
||||
|
||||
/// An axis aligned rectangle represented by its minimum and maximum coordinates.
|
||||
#[repr(C)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")))]
|
||||
pub struct TypedBox2D<T, U> {
|
||||
pub min: TypedPoint2D<T, U>,
|
||||
pub max: TypedPoint2D<T, U>,
|
||||
}
|
||||
|
||||
/// The default box 2d type with no unit.
|
||||
pub type Box2D<T> = TypedBox2D<T, UnknownUnit>;
|
||||
|
||||
impl<T: Hash, U> Hash for TypedBox2D<T, U> {
|
||||
fn hash<H: Hasher>(&self, h: &mut H) {
|
||||
self.min.hash(h);
|
||||
self.max.hash(h);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> Copy for TypedBox2D<T, U> {}
|
||||
|
||||
impl<T: Copy, U> Clone for TypedBox2D<T, U> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq, U> PartialEq<TypedBox2D<T, U>> for TypedBox2D<T, U> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.min.eq(&other.min) && self.max.eq(&other.max)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq, U> Eq for TypedBox2D<T, U> {}
|
||||
|
||||
impl<T: fmt::Debug, U> fmt::Debug for TypedBox2D<T, U> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "TypedBox2D({:?}, {:?})", self.min, self.max)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display, U> fmt::Display for TypedBox2D<T, U> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "Box2D({}, {})", self.min, self.max)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U> {
|
||||
/// Constructor.
|
||||
pub fn new(min: TypedPoint2D<T, U>, max: TypedPoint2D<T, U>) -> Self {
|
||||
TypedBox2D {
|
||||
min,
|
||||
max,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + Zero + PartialOrd,
|
||||
{
|
||||
/// Creates a Box2D of the given size, at offset zero.
|
||||
#[inline]
|
||||
pub fn from_size(size: TypedSize2D<T, U>) -> Self {
|
||||
let zero = TypedPoint2D::zero();
|
||||
let point = size.to_vector().to_point();
|
||||
TypedBox2D::from_points(&[zero, point])
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + PartialOrd,
|
||||
{
|
||||
/// Returns true if the box has a negative area.
|
||||
///
|
||||
/// The common interpretation for a negative box is to consider it empty. It can be obtained
|
||||
/// by calculating the intersection of two boxes that do not intersect.
|
||||
#[inline]
|
||||
pub fn is_negative(&self) -> bool {
|
||||
self.max.x < self.min.x || self.max.y < self.min.y
|
||||
}
|
||||
|
||||
/// Returns true if the size is zero or negative.
|
||||
#[inline]
|
||||
pub fn is_empty_or_negative(&self) -> bool {
|
||||
self.max.x <= self.min.x || self.max.y <= self.min.y
|
||||
}
|
||||
|
||||
/// Returns true if the two boxes intersect.
|
||||
#[inline]
|
||||
pub fn intersects(&self, other: &Self) -> bool {
|
||||
self.min.x < other.max.x
|
||||
&& self.max.x > other.min.x
|
||||
&& self.min.y < other.max.y
|
||||
&& self.max.y > other.min.y
|
||||
}
|
||||
|
||||
/// Computes the intersection of two boxes.
|
||||
///
|
||||
/// The result is a negative box if the boxes do not intersect.
|
||||
#[inline]
|
||||
pub fn intersection(&self, other: &Self) -> Self {
|
||||
TypedBox2D {
|
||||
min: point2(
|
||||
max(self.min.x, other.min.x),
|
||||
max(self.min.y, other.min.y),
|
||||
),
|
||||
max: point2(
|
||||
min(self.max.x, other.max.x),
|
||||
min(self.max.y, other.max.y),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the intersection of two boxes, returning `None` if the boxes do not intersect.
|
||||
#[inline]
|
||||
pub fn try_intersection(&self, other: &Self) -> Option<Self> {
|
||||
let intersection = self.intersection(other);
|
||||
|
||||
if intersection.is_negative() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(intersection)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + Add<T, Output = T>,
|
||||
{
|
||||
/// Returns the same box, translated by a vector.
|
||||
#[inline]
|
||||
pub fn translate(&self, by: &TypedVector2D<T, U>) -> Self {
|
||||
Self::new(self.min + *by, self.max + *by)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + PartialOrd + Zero,
|
||||
{
|
||||
/// Returns true if this box contains the point. Points are considered
|
||||
/// in the box if they are on the front, left or top faces, but outside if they
|
||||
/// are on the back, right or bottom faces.
|
||||
#[inline]
|
||||
pub fn contains(&self, p: &TypedPoint2D<T, U>) -> bool {
|
||||
self.min.x <= p.x && p.x < self.max.x
|
||||
&& self.min.y <= p.y && p.y < self.max.y
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + PartialOrd + Zero + Sub<T, Output = T>,
|
||||
{
|
||||
/// Returns true if this box contains the interior of the other box. Always
|
||||
/// returns true if other is empty, and always returns false if other is
|
||||
/// nonempty but this box is empty.
|
||||
#[inline]
|
||||
pub fn contains_box(&self, other: &Self) -> bool {
|
||||
other.is_empty_or_negative()
|
||||
|| (self.min.x <= other.min.x && other.max.x <= self.max.x
|
||||
&& self.min.y <= other.min.y && other.max.y <= self.max.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + Sub<T, Output = T>,
|
||||
{
|
||||
#[inline]
|
||||
pub fn size(&self)-> TypedSize2D<T, U> {
|
||||
(self.max - self.min).to_size()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_rect(&self) -> TypedRect<T, U> {
|
||||
TypedRect {
|
||||
origin: self.min,
|
||||
size: self.size(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + PartialEq + Add<T, Output = T> + Sub<T, Output = T>,
|
||||
{
|
||||
/// Inflates the box by the specified sizes on each side respectively.
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn inflate(&self, width: T, height: T) -> Self {
|
||||
TypedBox2D {
|
||||
min: point2(self.min.x - width, self.min.y - height),
|
||||
max: point2(self.max.x + width, self.max.y + height),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + Zero + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
|
||||
{
|
||||
/// Calculate the size and position of an inner box.
|
||||
///
|
||||
/// Subtracts the side offsets from all sides. The horizontal, vertical
|
||||
/// and applicate offsets must not be larger than the original side length.
|
||||
pub fn inner_box(&self, offsets: TypedSideOffsets2D<T, U>) -> Self {
|
||||
TypedBox2D {
|
||||
min: self.min + vec2(offsets.left, offsets.top),
|
||||
max: self.max - vec2(offsets.right, offsets.bottom),
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the b and position of an outer box.
|
||||
///
|
||||
/// Add the offsets to all sides. The expanded box is returned.
|
||||
pub fn outer_box(&self, offsets: TypedSideOffsets2D<T, U>) -> Self {
|
||||
TypedBox2D {
|
||||
min: self.min - vec2(offsets.left, offsets.top),
|
||||
max: self.max + vec2(offsets.right, offsets.bottom),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + Zero + PartialOrd,
|
||||
{
|
||||
/// Returns the smallest box containing all of the provided points.
|
||||
pub fn from_points<I>(points: I) -> Self
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<TypedPoint2D<T, U>>,
|
||||
{
|
||||
let mut points = points.into_iter();
|
||||
|
||||
// Need at least 2 different points for a valid box (ie: volume > 0).
|
||||
let (mut min_x, mut min_y) = match points.next() {
|
||||
Some(first) => (first.borrow().x, first.borrow().y),
|
||||
None => return TypedBox2D::zero(),
|
||||
};
|
||||
let (mut max_x, mut max_y) = (min_x, min_y);
|
||||
|
||||
{
|
||||
let mut assign_min_max = |point: I::Item| {
|
||||
let p = point.borrow();
|
||||
if p.x < min_x {
|
||||
min_x = p.x
|
||||
}
|
||||
if p.x > max_x {
|
||||
max_x = p.x
|
||||
}
|
||||
if p.y < min_y {
|
||||
min_y = p.y
|
||||
}
|
||||
if p.y > max_y {
|
||||
max_y = p.y
|
||||
}
|
||||
};
|
||||
|
||||
match points.next() {
|
||||
Some(second) => assign_min_max(second),
|
||||
None => return TypedBox2D::zero(),
|
||||
}
|
||||
|
||||
for point in points {
|
||||
assign_min_max(point);
|
||||
}
|
||||
}
|
||||
|
||||
TypedBox2D {
|
||||
min: point2(min_x, min_y),
|
||||
max: point2(max_x, max_y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + One + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
|
||||
{
|
||||
/// Linearly interpolate between this box and another box.
|
||||
///
|
||||
/// `t` is expected to be between zero and one.
|
||||
#[inline]
|
||||
pub fn lerp(&self, other: Self, t: T) -> Self {
|
||||
Self::new(
|
||||
self.min.lerp(other.min, t),
|
||||
self.max.lerp(other.max, t),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + One + Add<Output = T> + Div<Output = T>,
|
||||
{
|
||||
pub fn center(&self) -> TypedPoint2D<T, U> {
|
||||
let two = T::one() + T::one();
|
||||
(self.min + self.max.to_vector()) / two
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + PartialOrd,
|
||||
{
|
||||
#[inline]
|
||||
pub fn union(&self, other: &Self) -> Self {
|
||||
TypedBox2D {
|
||||
min: point2(
|
||||
min(self.min.x, other.min.x),
|
||||
min(self.min.y, other.min.y),
|
||||
),
|
||||
max: point2(
|
||||
max(self.max.x, other.max.x),
|
||||
max(self.max.y, other.max.y),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
#[inline]
|
||||
pub fn scale<S: Copy>(&self, x: S, y: S) -> Self
|
||||
where
|
||||
T: Mul<S, Output = T>
|
||||
{
|
||||
TypedBox2D {
|
||||
min: point2(self.min.x * x, self.min.y * y),
|
||||
max: point2(self.max.x * x, self.max.y * y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + Mul<T, Output = T> + Sub<T, Output = T>,
|
||||
{
|
||||
#[inline]
|
||||
pub fn area(&self) -> T {
|
||||
let size = self.size();
|
||||
size.width * size.height
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + Zero,
|
||||
{
|
||||
/// Constructor, setting all sides to zero.
|
||||
pub fn zero() -> Self {
|
||||
TypedBox2D::new(TypedPoint2D::zero(), TypedPoint2D::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
/// Returns true if the size is zero.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.min.x == self.max.x || self.min.y == self.max.y
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Mul<T> for TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + Mul<T, Output = T>,
|
||||
{
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn mul(self, scale: T) -> Self {
|
||||
TypedBox2D::new(self.min * scale, self.max * scale)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Div<T> for TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + Div<T, Output = T>,
|
||||
{
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn div(self, scale: T) -> Self {
|
||||
TypedBox2D::new(self.min / scale, self.max / scale)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U1, U2> Mul<TypedScale<T, U1, U2>> for TypedBox2D<T, U1>
|
||||
where
|
||||
T: Copy + Mul<T, Output = T>,
|
||||
{
|
||||
type Output = TypedBox2D<T, U2>;
|
||||
#[inline]
|
||||
fn mul(self, scale: TypedScale<T, U1, U2>) -> TypedBox2D<T, U2> {
|
||||
TypedBox2D::new(self.min * scale, self.max * scale)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U1, U2> Div<TypedScale<T, U1, U2>> for TypedBox2D<T, U2>
|
||||
where
|
||||
T: Copy + Div<T, Output = T>,
|
||||
{
|
||||
type Output = TypedBox2D<T, U1>;
|
||||
#[inline]
|
||||
fn div(self, scale: TypedScale<T, U1, U2>) -> TypedBox2D<T, U1> {
|
||||
TypedBox2D::new(self.min / scale, self.max / scale)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Unit> TypedBox2D<T, Unit>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
/// Drop the units, preserving only the numeric value.
|
||||
pub fn to_untyped(&self) -> Box2D<T> {
|
||||
TypedBox2D::new(self.min.to_untyped(), self.max.to_untyped())
|
||||
}
|
||||
|
||||
/// Tag a unitless value with units.
|
||||
pub fn from_untyped(c: &Box2D<T>) -> TypedBox2D<T, Unit> {
|
||||
TypedBox2D::new(
|
||||
TypedPoint2D::from_untyped(&c.min),
|
||||
TypedPoint2D::from_untyped(&c.max),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T0, Unit> TypedBox2D<T0, Unit>
|
||||
where
|
||||
T0: NumCast + Copy,
|
||||
{
|
||||
/// Cast from one numeric representation to another, preserving the units.
|
||||
///
|
||||
/// When casting from floating point to integer coordinates, the decimals are truncated
|
||||
/// as one would expect from a simple cast, but this behavior does not always make sense
|
||||
/// geometrically. Consider using round(), round_in or round_out() before casting.
|
||||
pub fn cast<T1: NumCast + Copy>(&self) -> TypedBox2D<T1, Unit> {
|
||||
TypedBox2D::new(
|
||||
self.min.cast(),
|
||||
self.max.cast(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Fallible cast from one numeric representation to another, preserving the units.
|
||||
///
|
||||
/// When casting from floating point to integer coordinates, the decimals are truncated
|
||||
/// as one would expect from a simple cast, but this behavior does not always make sense
|
||||
/// geometrically. Consider using round(), round_in or round_out() before casting.
|
||||
pub fn try_cast<T1: NumCast + Copy>(&self) -> Option<TypedBox2D<T1, Unit>> {
|
||||
match (self.min.try_cast(), self.max.try_cast()) {
|
||||
(Some(a), Some(b)) => Some(TypedBox2D::new(a, b)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Round,
|
||||
{
|
||||
/// Return a box with edges rounded to integer coordinates, such that
|
||||
/// the returned box has the same set of pixel centers as the original
|
||||
/// one.
|
||||
/// Values equal to 0.5 round up.
|
||||
/// Suitable for most places where integral device coordinates
|
||||
/// are needed, but note that any translation should be applied first to
|
||||
/// avoid pixel rounding errors.
|
||||
/// Note that this is *not* rounding to nearest integer if the values are negative.
|
||||
/// They are always rounding as floor(n + 0.5).
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn round(&self) -> Self {
|
||||
TypedBox2D::new(self.min.round(), self.max.round())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox2D<T, U>
|
||||
where
|
||||
T: Floor + Ceil,
|
||||
{
|
||||
/// Return a box with faces/edges rounded to integer coordinates, such that
|
||||
/// the original box contains the resulting box.
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn round_in(&self) -> Self {
|
||||
let min = self.min.ceil();
|
||||
let max = self.max.floor();
|
||||
TypedBox2D { min, max }
|
||||
}
|
||||
|
||||
/// Return a box with faces/edges rounded to integer coordinates, such that
|
||||
/// the original box is contained in the resulting box.
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn round_out(&self) -> Self {
|
||||
let min = self.min.floor();
|
||||
let max = self.max.ceil();
|
||||
TypedBox2D { min, max }
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience functions for common casts
|
||||
impl<T: NumCast + Copy, Unit> TypedBox2D<T, Unit> {
|
||||
/// Cast into an `f32` box.
|
||||
pub fn to_f32(&self) -> TypedBox2D<f32, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `f64` box.
|
||||
pub fn to_f64(&self) -> TypedBox2D<f64, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `usize` box, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point boxes, it is worth considering whether
|
||||
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
|
||||
/// obtain the desired conversion behavior.
|
||||
pub fn to_usize(&self) -> TypedBox2D<usize, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `u32` box, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point boxes, it is worth considering whether
|
||||
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
|
||||
/// obtain the desired conversion behavior.
|
||||
pub fn to_u32(&self) -> TypedBox2D<u32, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `i32` box, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point boxes, it is worth considering whether
|
||||
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
|
||||
/// obtain the desired conversion behavior.
|
||||
pub fn to_i32(&self) -> TypedBox2D<i32, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `i64` box, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point boxes, it is worth considering whether
|
||||
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
|
||||
/// obtain the desired conversion behavior.
|
||||
pub fn to_i64(&self) -> TypedBox2D<i64, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> From<TypedSize2D<T, U>> for TypedBox2D<T, U>
|
||||
where
|
||||
T: Copy + Zero + PartialOrd,
|
||||
{
|
||||
fn from(b: TypedSize2D<T, U>) -> Self {
|
||||
Self::from_size(b)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use side_offsets::SideOffsets2D;
|
||||
use size::size2;
|
||||
use point::Point2D;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_size() {
|
||||
let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
|
||||
assert_eq!(b.size().width, 20.0);
|
||||
assert_eq!(b.size().height, 20.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_center() {
|
||||
let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
|
||||
assert_eq!(b.center(), Point2D::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_area() {
|
||||
let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
|
||||
assert_eq!(b.area(), 400.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_points() {
|
||||
let b = Box2D::from_points(&[point2(50.0, 160.0), point2(100.0, 25.0)]);
|
||||
assert_eq!(b.min, point2(50.0, 25.0));
|
||||
assert_eq!(b.max, point2(100.0, 160.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round_in() {
|
||||
let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_in();
|
||||
assert_eq!(b.min.x, -25.0);
|
||||
assert_eq!(b.min.y, -40.0);
|
||||
assert_eq!(b.max.x, 60.0);
|
||||
assert_eq!(b.max.y, 36.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round_out() {
|
||||
let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_out();
|
||||
assert_eq!(b.min.x,-26.0);
|
||||
assert_eq!(b.min.y, -41.0);
|
||||
assert_eq!(b.max.x, 61.0);
|
||||
assert_eq!(b.max.y, 37.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round() {
|
||||
let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round();
|
||||
assert_eq!(b.min.x,-26.0);
|
||||
assert_eq!(b.min.y, -40.0);
|
||||
assert_eq!(b.max.x, 60.0);
|
||||
assert_eq!(b.max.y, 37.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_size() {
|
||||
let b = Box2D::from_size(size2(30.0, 40.0));
|
||||
assert!(b.min == Point2D::zero());
|
||||
assert!(b.size().width == 30.0);
|
||||
assert!(b.size().height == 40.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inner_box() {
|
||||
let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]);
|
||||
let b = b.inner_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0));
|
||||
assert_eq!(b.max.x, 80.0);
|
||||
assert_eq!(b.max.y, 155.0);
|
||||
assert_eq!(b.min.x, 60.0);
|
||||
assert_eq!(b.min.y, 35.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_outer_box() {
|
||||
let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]);
|
||||
let b = b.outer_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0));
|
||||
assert_eq!(b.max.x, 120.0);
|
||||
assert_eq!(b.max.y, 165.0);
|
||||
assert_eq!(b.min.x, 40.0);
|
||||
assert_eq!(b.min.y, 15.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_translate() {
|
||||
let size = size2(15.0, 15.0);
|
||||
let mut center = (size / 2.0).to_vector().to_point();
|
||||
let b = Box2D::from_size(size);
|
||||
assert_eq!(b.center(), center);
|
||||
let translation = vec2(10.0, 2.5);
|
||||
let b = b.translate(&translation);
|
||||
center += translation;
|
||||
assert_eq!(b.center(), center);
|
||||
assert_eq!(b.max.x, 25.0);
|
||||
assert_eq!(b.max.y, 17.5);
|
||||
assert_eq!(b.min.x, 10.0);
|
||||
assert_eq!(b.min.y, 2.5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_union() {
|
||||
let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(0.0, 20.0)]);
|
||||
let b2 = Box2D::from_points(&[point2(0.0, 20.0), point2(20.0, -20.0)]);
|
||||
let b = b1.union(&b2);
|
||||
assert_eq!(b.max.x, 20.0);
|
||||
assert_eq!(b.max.y, 20.0);
|
||||
assert_eq!(b.min.x, -20.0);
|
||||
assert_eq!(b.min.y, -20.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_intersects() {
|
||||
let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
|
||||
let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
|
||||
assert!(b1.intersects(&b2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_intersection() {
|
||||
let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
|
||||
let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
|
||||
let b = b1.intersection(&b2);
|
||||
assert_eq!(b.max.x, 10.0);
|
||||
assert_eq!(b.max.y, 20.0);
|
||||
assert_eq!(b.min.x, -10.0);
|
||||
assert_eq!(b.min.y, -20.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_intersection() {
|
||||
let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
|
||||
let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
|
||||
assert!(b1.try_intersection(&b2).is_some());
|
||||
|
||||
let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(-10.0, 20.0)]);
|
||||
let b2 = Box2D::from_points(&[point2(10.0, 20.0), point2(15.0, -20.0)]);
|
||||
assert!(b1.try_intersection(&b2).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scale() {
|
||||
let b = Box2D::from_points(&[point2(-10.0, -10.0), point2(10.0, 10.0)]);
|
||||
let b = b.scale(0.5, 0.5);
|
||||
assert_eq!(b.max.x, 5.0);
|
||||
assert_eq!(b.max.y, 5.0);
|
||||
assert_eq!(b.min.x, -5.0);
|
||||
assert_eq!(b.min.y, -5.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lerp() {
|
||||
let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(-10.0, -10.0)]);
|
||||
let b2 = Box2D::from_points(&[point2(10.0, 10.0), point2(20.0, 20.0)]);
|
||||
let b = b1.lerp(b2, 0.5);
|
||||
assert_eq!(b.center(), Point2D::zero());
|
||||
assert_eq!(b.size().width, 10.0);
|
||||
assert_eq!(b.size().height, 10.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_contains() {
|
||||
let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
|
||||
assert!(b.contains(&point2(-15.3, 10.5)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_contains_box() {
|
||||
let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
|
||||
let b2 = Box2D::from_points(&[point2(-14.3, -16.5), point2(6.7, 17.6)]);
|
||||
assert!(b1.contains_box(&b2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inflate() {
|
||||
let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
|
||||
let b = b.inflate(10.0, 5.0);
|
||||
assert_eq!(b.size().width, 60.0);
|
||||
assert_eq!(b.size().height, 50.0);
|
||||
assert_eq!(b.center(), Point2D::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_empty() {
|
||||
for i in 0..2 {
|
||||
let mut coords_neg = [-20.0, -20.0];
|
||||
let mut coords_pos = [20.0, 20.0];
|
||||
coords_neg[i] = 0.0;
|
||||
coords_pos[i] = 0.0;
|
||||
let b = Box2D::from_points(&[Point2D::from(coords_neg), Point2D::from(coords_pos)]);
|
||||
assert!(b.is_empty());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,842 @@
|
|||
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::UnknownUnit;
|
||||
use length::Length;
|
||||
use scale::TypedScale;
|
||||
use num::*;
|
||||
use point::TypedPoint3D;
|
||||
use vector::TypedVector3D;
|
||||
use size::TypedSize3D;
|
||||
use approxord::{min, max};
|
||||
|
||||
use num_traits::NumCast;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use core::borrow::Borrow;
|
||||
use core::cmp::PartialOrd;
|
||||
use core::fmt;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::ops::{Add, Div, Mul, Sub};
|
||||
|
||||
|
||||
/// An axis aligned 3D box represented by its minimum and maximum coordinates.
|
||||
#[repr(C)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")))]
|
||||
pub struct TypedBox3D<T, U> {
|
||||
pub min: TypedPoint3D<T, U>,
|
||||
pub max: TypedPoint3D<T, U>,
|
||||
}
|
||||
|
||||
/// The default box 3d type with no unit.
|
||||
pub type Box3D<T> = TypedBox3D<T, UnknownUnit>;
|
||||
|
||||
impl<T: Hash, U> Hash for TypedBox3D<T, U> {
|
||||
fn hash<H: Hasher>(&self, h: &mut H) {
|
||||
self.min.hash(h);
|
||||
self.max.hash(h);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> Copy for TypedBox3D<T, U> {}
|
||||
|
||||
impl<T: Copy, U> Clone for TypedBox3D<T, U> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq, U> PartialEq<TypedBox3D<T, U>> for TypedBox3D<T, U> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.min.eq(&other.min) && self.max.eq(&other.max)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq, U> Eq for TypedBox3D<T, U> {}
|
||||
|
||||
impl<T: fmt::Debug, U> fmt::Debug for TypedBox3D<T, U> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "TypedBox3D({:?}, {:?})", self.min, self.max)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display, U> fmt::Display for TypedBox3D<T, U> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "Box3D({}, {})", self.min, self.max)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U> {
|
||||
/// Constructor.
|
||||
pub fn new(min: TypedPoint3D<T, U>, max: TypedPoint3D<T, U>) -> Self {
|
||||
TypedBox3D {
|
||||
min,
|
||||
max,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + Zero + PartialOrd,
|
||||
{
|
||||
/// Creates a Box3D of the given size, at offset zero.
|
||||
#[inline]
|
||||
pub fn from_size(size: TypedSize3D<T, U>) -> Self {
|
||||
let zero = TypedPoint3D::zero();
|
||||
let point = size.to_vector().to_point();
|
||||
TypedBox3D::from_points(&[zero, point])
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + PartialOrd,
|
||||
{
|
||||
/// Returns true if the box has a negative volume.
|
||||
///
|
||||
/// The common interpretation for a negative box is to consider it empty. It can be obtained
|
||||
/// by calculating the intersection of two boxes that do not intersect.
|
||||
#[inline]
|
||||
pub fn is_negative(&self) -> bool {
|
||||
self.max.x < self.min.x || self.max.y < self.min.y || self.max.z < self.min.z
|
||||
}
|
||||
|
||||
/// Returns true if the size is zero or negative.
|
||||
#[inline]
|
||||
pub fn is_empty_or_negative(&self) -> bool {
|
||||
self.max.x <= self.min.x || self.max.y <= self.min.y || self.max.z <= self.min.z
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
pub fn intersects(&self, other: &Self) -> bool {
|
||||
self.min.x < other.max.x
|
||||
&& self.max.x > other.min.x
|
||||
&& self.min.y < other.max.y
|
||||
&& self.max.y > other.min.y
|
||||
&& self.min.z < other.max.z
|
||||
&& self.max.z > other.min.z
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_intersection(&self, other: &Self) -> Option<Self> {
|
||||
if !self.intersects(other) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(self.intersection(other))
|
||||
}
|
||||
|
||||
pub fn intersection(&self, other: &Self) -> Self {
|
||||
let intersection_min = TypedPoint3D::new(
|
||||
max(self.min.x, other.min.x),
|
||||
max(self.min.y, other.min.y),
|
||||
max(self.min.z, other.min.z),
|
||||
);
|
||||
|
||||
let intersection_max = TypedPoint3D::new(
|
||||
min(self.max.x, other.max.x),
|
||||
min(self.max.y, other.max.y),
|
||||
min(self.max.z, other.max.z),
|
||||
);
|
||||
|
||||
TypedBox3D::new(
|
||||
intersection_min,
|
||||
intersection_max,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + Add<T, Output = T>,
|
||||
{
|
||||
/// Returns the same box3d, translated by a vector.
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn translate(&self, by: &TypedVector3D<T, U>) -> Self {
|
||||
Self::new(self.min + *by, self.max + *by)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + PartialOrd + Zero,
|
||||
{
|
||||
/// Returns true if this box3d contains the point. Points are considered
|
||||
/// in the box3d if they are on the front, left or top faces, but outside if they
|
||||
/// are on the back, right or bottom faces.
|
||||
#[inline]
|
||||
pub fn contains(&self, other: &TypedPoint3D<T, U>) -> bool {
|
||||
self.min.x <= other.x && other.x < self.max.x
|
||||
&& self.min.y <= other.y && other.y < self.max.y
|
||||
&& self.min.z <= other.z && other.z < self.max.z
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + PartialOrd + Zero + Sub<T, Output = T>,
|
||||
{
|
||||
/// Returns true if this box3d contains the interior of the other box3d. Always
|
||||
/// returns true if other is empty, and always returns false if other is
|
||||
/// nonempty but this box3d is empty.
|
||||
#[inline]
|
||||
pub fn contains_box(&self, other: &Self) -> bool {
|
||||
other.is_empty_or_negative()
|
||||
|| (self.min.x <= other.min.x && other.max.x <= self.max.x
|
||||
&& self.min.y <= other.min.y && other.max.y <= self.max.y
|
||||
&& self.min.z <= other.min.z && other.max.z <= self.max.z)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + Sub<T, Output = T>,
|
||||
{
|
||||
#[inline]
|
||||
pub fn size(&self)-> TypedSize3D<T, U> {
|
||||
TypedSize3D::new(
|
||||
self.max.x - self.min.x,
|
||||
self.max.y - self.min.y,
|
||||
self.max.z - self.min.z,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + PartialEq + Add<T, Output = T> + Sub<T, Output = T>,
|
||||
{
|
||||
/// Inflates the box by the specified sizes on each side respectively.
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn inflate(&self, width: T, height: T, depth: T) -> Self {
|
||||
TypedBox3D::new(
|
||||
TypedPoint3D::new(self.min.x - width, self.min.y - height, self.min.z - depth),
|
||||
TypedPoint3D::new(self.max.x + width, self.max.y + height, self.max.z + depth),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn inflate_typed(&self, width: Length<T, U>, height: Length<T, U>, depth: Length<T, U>) -> Self {
|
||||
self.inflate(width.get(), height.get(), depth.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + Zero + PartialOrd,
|
||||
{
|
||||
/// Returns the smallest box containing all of the provided points.
|
||||
pub fn from_points<I>(points: I) -> Self
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<TypedPoint3D<T, U>>,
|
||||
{
|
||||
let mut points = points.into_iter();
|
||||
|
||||
// Need at least 2 different points for a valid box3d (ie: volume > 0).
|
||||
let (mut min_x, mut min_y, mut min_z) = match points.next() {
|
||||
Some(first) => (first.borrow().x, first.borrow().y, first.borrow().z),
|
||||
None => return TypedBox3D::zero(),
|
||||
};
|
||||
let (mut max_x, mut max_y, mut max_z) = (min_x, min_y, min_z);
|
||||
|
||||
{
|
||||
let mut assign_min_max = |point: I::Item| {
|
||||
let p = point.borrow();
|
||||
if p.x < min_x {
|
||||
min_x = p.x
|
||||
}
|
||||
if p.x > max_x {
|
||||
max_x = p.x
|
||||
}
|
||||
if p.y < min_y {
|
||||
min_y = p.y
|
||||
}
|
||||
if p.y > max_y {
|
||||
max_y = p.y
|
||||
}
|
||||
if p.z < min_z {
|
||||
min_z = p.z
|
||||
}
|
||||
if p.z > max_z {
|
||||
max_z = p.z
|
||||
}
|
||||
};
|
||||
|
||||
match points.next() {
|
||||
Some(second) => assign_min_max(second),
|
||||
None => return TypedBox3D::zero(),
|
||||
}
|
||||
|
||||
for point in points {
|
||||
assign_min_max(point);
|
||||
}
|
||||
}
|
||||
|
||||
Self::new(TypedPoint3D::new(min_x, min_y, min_z), TypedPoint3D::new(max_x, max_y, max_z))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + One + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
|
||||
{
|
||||
/// Linearly interpolate between this box3d and another box3d.
|
||||
///
|
||||
/// `t` is expected to be between zero and one.
|
||||
#[inline]
|
||||
pub fn lerp(&self, other: Self, t: T) -> Self {
|
||||
Self::new(
|
||||
self.min.lerp(other.min, t),
|
||||
self.max.lerp(other.max, t),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + One + Add<Output = T> + Div<Output = T>,
|
||||
{
|
||||
pub fn center(&self) -> TypedPoint3D<T, U> {
|
||||
let two = T::one() + T::one();
|
||||
(self.min + self.max.to_vector()) / two
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + Clone + PartialOrd + Add<T, Output = T> + Sub<T, Output = T> + Zero,
|
||||
{
|
||||
#[inline]
|
||||
pub fn union(&self, other: &Self) -> Self {
|
||||
TypedBox3D::new(
|
||||
TypedPoint3D::new(
|
||||
min(self.min.x, other.min.x),
|
||||
min(self.min.y, other.min.y),
|
||||
min(self.min.z, other.min.z),
|
||||
),
|
||||
TypedPoint3D::new(
|
||||
max(self.max.x, other.max.x),
|
||||
max(self.max.y, other.max.y),
|
||||
max(self.max.z, other.max.z),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
#[inline]
|
||||
pub fn scale<S: Copy>(&self, x: S, y: S, z: S) -> Self
|
||||
where
|
||||
T: Mul<S, Output = T>
|
||||
{
|
||||
TypedBox3D::new(
|
||||
TypedPoint3D::new(self.min.x * x, self.min.y * y, self.min.z * z),
|
||||
TypedPoint3D::new(self.max.x * x, self.max.y * y, self.max.z * z),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + Mul<T, Output = T> + Sub<T, Output = T>,
|
||||
{
|
||||
#[inline]
|
||||
pub fn volume(&self) -> T {
|
||||
let size = self.size();
|
||||
size.width * size.height * size.depth
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn xy_area(&self) -> T {
|
||||
let size = self.size();
|
||||
size.width * size.height
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn yz_area(&self) -> T {
|
||||
let size = self.size();
|
||||
size.depth * size.height
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn xz_area(&self) -> T {
|
||||
let size = self.size();
|
||||
size.depth * size.width
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + Zero,
|
||||
{
|
||||
/// Constructor, setting all sides to zero.
|
||||
pub fn zero() -> Self {
|
||||
TypedBox3D::new(TypedPoint3D::zero(), TypedPoint3D::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
/// Returns true if the volume is zero.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.min.x == self.max.x || self.min.y == self.max.y || self.min.z == self.max.z
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Mul<T> for TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + Mul<T, Output = T>,
|
||||
{
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn mul(self, scale: T) -> Self {
|
||||
TypedBox3D::new(self.min * scale, self.max * scale)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Div<T> for TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + Div<T, Output = T>,
|
||||
{
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn div(self, scale: T) -> Self {
|
||||
TypedBox3D::new(self.min / scale, self.max / scale)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U1, U2> Mul<TypedScale<T, U1, U2>> for TypedBox3D<T, U1>
|
||||
where
|
||||
T: Copy + Mul<T, Output = T>,
|
||||
{
|
||||
type Output = TypedBox3D<T, U2>;
|
||||
#[inline]
|
||||
fn mul(self, scale: TypedScale<T, U1, U2>) -> TypedBox3D<T, U2> {
|
||||
TypedBox3D::new(self.min * scale, self.max * scale)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U1, U2> Div<TypedScale<T, U1, U2>> for TypedBox3D<T, U2>
|
||||
where
|
||||
T: Copy + Div<T, Output = T>,
|
||||
{
|
||||
type Output = TypedBox3D<T, U1>;
|
||||
#[inline]
|
||||
fn div(self, scale: TypedScale<T, U1, U2>) -> TypedBox3D<T, U1> {
|
||||
TypedBox3D::new(self.min / scale, self.max / scale)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Unit> TypedBox3D<T, Unit>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
/// Drop the units, preserving only the numeric value.
|
||||
pub fn to_untyped(&self) -> Box3D<T> {
|
||||
TypedBox3D::new(self.min.to_untyped(), self.max.to_untyped())
|
||||
}
|
||||
|
||||
/// Tag a unitless value with units.
|
||||
pub fn from_untyped(c: &Box3D<T>) -> TypedBox3D<T, Unit> {
|
||||
TypedBox3D::new(
|
||||
TypedPoint3D::from_untyped(&c.min),
|
||||
TypedPoint3D::from_untyped(&c.max),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T0, Unit> TypedBox3D<T0, Unit>
|
||||
where
|
||||
T0: NumCast + Copy,
|
||||
{
|
||||
/// Cast from one numeric representation to another, preserving the units.
|
||||
///
|
||||
/// When casting from floating point to integer coordinates, the decimals are truncated
|
||||
/// as one would expect from a simple cast, but this behavior does not always make sense
|
||||
/// geometrically. Consider using round(), round_in or round_out() before casting.
|
||||
pub fn cast<T1: NumCast + Copy>(&self) -> TypedBox3D<T1, Unit> {
|
||||
TypedBox3D::new(
|
||||
self.min.cast(),
|
||||
self.max.cast(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Fallible cast from one numeric representation to another, preserving the units.
|
||||
///
|
||||
/// When casting from floating point to integer coordinates, the decimals are truncated
|
||||
/// as one would expect from a simple cast, but this behavior does not always make sense
|
||||
/// geometrically. Consider using round(), round_in or round_out() before casting.
|
||||
pub fn try_cast<T1: NumCast + Copy>(&self) -> Option<TypedBox3D<T1, Unit>> {
|
||||
match (self.min.try_cast(), self.max.try_cast()) {
|
||||
(Some(a), Some(b)) => Some(TypedBox3D::new(a, b)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Round,
|
||||
{
|
||||
/// Return a box3d with edges rounded to integer coordinates, such that
|
||||
/// the returned box3d has the same set of pixel centers as the original
|
||||
/// one.
|
||||
/// Values equal to 0.5 round up.
|
||||
/// Suitable for most places where integral device coordinates
|
||||
/// are needed, but note that any translation should be applied first to
|
||||
/// avoid pixel rounding errors.
|
||||
/// Note that this is *not* rounding to nearest integer if the values are negative.
|
||||
/// They are always rounding as floor(n + 0.5).
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn round(&self) -> Self {
|
||||
TypedBox3D::new(self.min.round(), self.max.round())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedBox3D<T, U>
|
||||
where
|
||||
T: Floor + Ceil,
|
||||
{
|
||||
/// Return a box3d with faces/edges rounded to integer coordinates, such that
|
||||
/// the original box3d contains the resulting box3d.
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn round_in(&self) -> Self {
|
||||
TypedBox3D {
|
||||
min: self.min.ceil(),
|
||||
max: self.max.floor(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a box3d with faces/edges rounded to integer coordinates, such that
|
||||
/// the original box3d is contained in the resulting box3d.
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn round_out(&self) -> Self {
|
||||
TypedBox3D {
|
||||
min: self.min.floor(),
|
||||
max: self.max.ceil(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience functions for common casts
|
||||
impl<T: NumCast + Copy, Unit> TypedBox3D<T, Unit> {
|
||||
/// Cast into an `f32` box3d.
|
||||
pub fn to_f32(&self) -> TypedBox3D<f32, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `f64` box3d.
|
||||
pub fn to_f64(&self) -> TypedBox3D<f64, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `usize` box3d, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point cuboids, it is worth considering whether
|
||||
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
|
||||
/// obtain the desired conversion behavior.
|
||||
pub fn to_usize(&self) -> TypedBox3D<usize, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `u32` box3d, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point cuboids, it is worth considering whether
|
||||
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
|
||||
/// obtain the desired conversion behavior.
|
||||
pub fn to_u32(&self) -> TypedBox3D<u32, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `i32` box3d, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point cuboids, it is worth considering whether
|
||||
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
|
||||
/// obtain the desired conversion behavior.
|
||||
pub fn to_i32(&self) -> TypedBox3D<i32, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `i64` box3d, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point cuboids, it is worth considering whether
|
||||
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
|
||||
/// obtain the desired conversion behavior.
|
||||
pub fn to_i64(&self) -> TypedBox3D<i64, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> From<TypedSize3D<T, U>> for TypedBox3D<T, U>
|
||||
where
|
||||
T: Copy + Zero + PartialOrd,
|
||||
{
|
||||
fn from(b: TypedSize3D<T, U>) -> Self {
|
||||
Self::from_size(b)
|
||||
}
|
||||
}
|
||||
|
||||
/// Shorthand for `TypedBox3D::new(TypedPoint3D::new(x1, y1, z1), TypedPoint3D::new(x2, y2, z2))`.
|
||||
pub fn box3d<T: Copy, U>(min_x: T, min_y: T, min_z: T, max_x: T, max_y: T, max_z: T) -> TypedBox3D<T, U> {
|
||||
TypedBox3D::new(TypedPoint3D::new(min_x, min_y, min_z), TypedPoint3D::new(max_x, max_y, max_z))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use vector::vec3;
|
||||
use size::size3;
|
||||
use point::{point3, Point3D};
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_new() {
|
||||
let b = Box3D::new(point3(-1.0, -1.0, -1.0), point3(1.0, 1.0, 1.0));
|
||||
assert!(b.min.x == -1.0);
|
||||
assert!(b.min.y == -1.0);
|
||||
assert!(b.min.z == -1.0);
|
||||
assert!(b.max.x == 1.0);
|
||||
assert!(b.max.y == 1.0);
|
||||
assert!(b.max.z == 1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_size() {
|
||||
let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0));
|
||||
assert!(b.size().width == 20.0);
|
||||
assert!(b.size().height == 20.0);
|
||||
assert!(b.size().depth == 20.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_center() {
|
||||
let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0));
|
||||
assert!(b.center() == Point3D::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_volume() {
|
||||
let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0));
|
||||
assert!(b.volume() == 8000.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_area() {
|
||||
let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0));
|
||||
assert!(b.xy_area() == 400.0);
|
||||
assert!(b.yz_area() == 400.0);
|
||||
assert!(b.xz_area() == 400.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_points() {
|
||||
let b = Box3D::from_points(&[point3(50.0, 160.0, 12.5), point3(100.0, 25.0, 200.0)]);
|
||||
assert!(b.min == point3(50.0, 25.0, 12.5));
|
||||
assert!(b.max == point3(100.0, 160.0, 200.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_max() {
|
||||
let b = Box3D::from_points(&[point3(50.0, 25.0, 12.5), point3(100.0, 160.0, 200.0)]);
|
||||
assert!(b.min.x == 50.0);
|
||||
assert!(b.min.y == 25.0);
|
||||
assert!(b.min.z == 12.5);
|
||||
assert!(b.max.x == 100.0);
|
||||
assert!(b.max.y == 160.0);
|
||||
assert!(b.max.z == 200.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round_in() {
|
||||
let b = Box3D::from_points(&[point3(-25.5, -40.4, -70.9), point3(60.3, 36.5, 89.8)]).round_in();
|
||||
assert!(b.min.x == -25.0);
|
||||
assert!(b.min.y == -40.0);
|
||||
assert!(b.min.z == -70.0);
|
||||
assert!(b.max.x == 60.0);
|
||||
assert!(b.max.y == 36.0);
|
||||
assert!(b.max.z == 89.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round_out() {
|
||||
let b = Box3D::from_points(&[point3(-25.5, -40.4, -70.9), point3(60.3, 36.5, 89.8)]).round_out();
|
||||
assert!(b.min.x == -26.0);
|
||||
assert!(b.min.y == -41.0);
|
||||
assert!(b.min.z == -71.0);
|
||||
assert!(b.max.x == 61.0);
|
||||
assert!(b.max.y == 37.0);
|
||||
assert!(b.max.z == 90.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round() {
|
||||
let b = Box3D::from_points(&[point3(-25.5, -40.4, -70.9), point3(60.3, 36.5, 89.8)]).round();
|
||||
assert!(b.min.x == -26.0);
|
||||
assert!(b.min.y == -40.0);
|
||||
assert!(b.min.z == -71.0);
|
||||
assert!(b.max.x == 60.0);
|
||||
assert!(b.max.y == 37.0);
|
||||
assert!(b.max.z == 90.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_size() {
|
||||
let b = Box3D::from_size(size3(30.0, 40.0, 50.0));
|
||||
assert!(b.min == Point3D::zero());
|
||||
assert!(b.size().width == 30.0);
|
||||
assert!(b.size().height == 40.0);
|
||||
assert!(b.size().depth == 50.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_translate() {
|
||||
let size = size3(15.0, 15.0, 200.0);
|
||||
let mut center = (size / 2.0).to_vector().to_point();
|
||||
let b = Box3D::from_size(size);
|
||||
assert!(b.center() == center);
|
||||
let translation = vec3(10.0, 2.5, 9.5);
|
||||
let b = b.translate(&translation);
|
||||
center += translation;
|
||||
assert!(b.center() == center);
|
||||
assert!(b.max.x == 25.0);
|
||||
assert!(b.max.y == 17.5);
|
||||
assert!(b.max.z == 209.5);
|
||||
assert!(b.min.x == 10.0);
|
||||
assert!(b.min.y == 2.5);
|
||||
assert!(b.min.z == 9.5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_union() {
|
||||
let b1 = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(0.0, 20.0, 20.0)]);
|
||||
let b2 = Box3D::from_points(&[point3(0.0, 20.0, 20.0), point3(20.0, -20.0, -20.0)]);
|
||||
let b = b1.union(&b2);
|
||||
assert!(b.max.x == 20.0);
|
||||
assert!(b.max.y == 20.0);
|
||||
assert!(b.max.z == 20.0);
|
||||
assert!(b.min.x == -20.0);
|
||||
assert!(b.min.y == -20.0);
|
||||
assert!(b.min.z == -20.0);
|
||||
assert!(b.volume() == (40.0 * 40.0 * 40.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_intersects() {
|
||||
let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(10.0, 20.0, 20.0)]);
|
||||
let b2 = Box3D::from_points(&[point3(-10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]);
|
||||
assert!(b1.intersects(&b2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_intersection() {
|
||||
let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(10.0, 20.0, 20.0)]);
|
||||
let b2 = Box3D::from_points(&[point3(-10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]);
|
||||
let b = b1.intersection(&b2);
|
||||
assert!(b.max.x == 10.0);
|
||||
assert!(b.max.y == 20.0);
|
||||
assert!(b.max.z == 20.0);
|
||||
assert!(b.min.x == -10.0);
|
||||
assert!(b.min.y == -20.0);
|
||||
assert!(b.min.z == -20.0);
|
||||
assert!(b.volume() == (20.0 * 40.0 * 40.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_intersection() {
|
||||
let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(10.0, 20.0, 20.0)]);
|
||||
let b2 = Box3D::from_points(&[point3(-10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]);
|
||||
assert!(b1.try_intersection(&b2).is_some());
|
||||
|
||||
let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(-10.0, 20.0, 20.0)]);
|
||||
let b2 = Box3D::from_points(&[point3(10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]);
|
||||
assert!(b1.try_intersection(&b2).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scale() {
|
||||
let b = Box3D::from_points(&[point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)]);
|
||||
let b = b.scale(0.5, 0.5, 0.5);
|
||||
assert!(b.max.x == 5.0);
|
||||
assert!(b.max.y == 5.0);
|
||||
assert!(b.max.z == 5.0);
|
||||
assert!(b.min.x == -5.0);
|
||||
assert!(b.min.y == -5.0);
|
||||
assert!(b.min.z == -5.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
let b = Box3D::<f64>::zero();
|
||||
assert!(b.max.x == 0.0);
|
||||
assert!(b.max.y == 0.0);
|
||||
assert!(b.max.z == 0.0);
|
||||
assert!(b.min.x == 0.0);
|
||||
assert!(b.min.y == 0.0);
|
||||
assert!(b.min.z == 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lerp() {
|
||||
let b1 = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(-10.0, -10.0, -10.0)]);
|
||||
let b2 = Box3D::from_points(&[point3(10.0, 10.0, 10.0), point3(20.0, 20.0, 20.0)]);
|
||||
let b = b1.lerp(b2, 0.5);
|
||||
assert!(b.center() == Point3D::zero());
|
||||
assert!(b.size().width == 10.0);
|
||||
assert!(b.size().height == 10.0);
|
||||
assert!(b.size().depth == 10.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_contains() {
|
||||
let b = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(20.0, 20.0, 20.0)]);
|
||||
assert!(b.contains(&point3(-15.3, 10.5, 18.4)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_contains_box() {
|
||||
let b1 = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(20.0, 20.0, 20.0)]);
|
||||
let b2 = Box3D::from_points(&[point3(-14.3, -16.5, -19.3), point3(6.7, 17.6, 2.5)]);
|
||||
assert!(b1.contains_box(&b2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inflate() {
|
||||
let b = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(20.0, 20.0, 20.0)]);
|
||||
let b = b.inflate(10.0, 5.0, 2.0);
|
||||
assert!(b.size().width == 60.0);
|
||||
assert!(b.size().height == 50.0);
|
||||
assert!(b.size().depth == 44.0);
|
||||
assert!(b.center() == Point3D::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_empty() {
|
||||
for i in 0..3 {
|
||||
let mut coords_neg = [-20.0, -20.0, -20.0];
|
||||
let mut coords_pos = [20.0, 20.0, 20.0];
|
||||
coords_neg[i] = 0.0;
|
||||
coords_pos[i] = 0.0;
|
||||
let b = Box3D::from_points(&[Point3D::from(coords_neg), Point3D::from(coords_pos)]);
|
||||
assert!(b.is_empty());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -70,6 +70,7 @@ extern crate rand;
|
|||
#[cfg(test)]
|
||||
use std as core;
|
||||
|
||||
pub use box2d::{TypedBox2D, Box2D};
|
||||
pub use length::Length;
|
||||
pub use scale::TypedScale;
|
||||
pub use transform2d::{Transform2D, TypedTransform2D};
|
||||
|
@ -80,6 +81,8 @@ pub use vector::{BoolVector2D, BoolVector3D, bvec2, bvec3};
|
|||
pub use homogen::HomogeneousVector;
|
||||
|
||||
pub use rect::{rect, Rect, TypedRect};
|
||||
pub use rigid::{RigidTransform3D, TypedRigidTransform3D};
|
||||
pub use box3d::{box3d, Box3D, TypedBox3D};
|
||||
pub use translation::{TypedTranslation2D, TypedTranslation3D};
|
||||
pub use rotation::{Angle, Rotation2D, Rotation3D, TypedRotation2D, TypedRotation3D};
|
||||
pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
|
||||
|
@ -90,11 +93,14 @@ pub use trig::Trig;
|
|||
mod macros;
|
||||
|
||||
pub mod approxeq;
|
||||
pub mod approxord;
|
||||
mod box2d;
|
||||
mod homogen;
|
||||
pub mod num;
|
||||
mod length;
|
||||
mod point;
|
||||
mod rect;
|
||||
mod rigid;
|
||||
mod rotation;
|
||||
mod scale;
|
||||
mod side_offsets;
|
||||
|
@ -104,9 +110,10 @@ mod transform3d;
|
|||
mod translation;
|
||||
mod trig;
|
||||
mod vector;
|
||||
mod box3d;
|
||||
|
||||
/// The default unit.
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct UnknownUnit;
|
||||
|
||||
/// Temporary alias to facilitate the transition to the new naming scheme
|
||||
|
|
|
@ -11,7 +11,7 @@ use super::UnknownUnit;
|
|||
use approxeq::ApproxEq;
|
||||
use length::Length;
|
||||
use scale::TypedScale;
|
||||
use size::TypedSize2D;
|
||||
use size::{TypedSize2D, TypedSize3D};
|
||||
#[cfg(feature = "mint")]
|
||||
use mint;
|
||||
use num::*;
|
||||
|
@ -69,6 +69,12 @@ impl<T: fmt::Display, U> fmt::Display for TypedPoint2D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Default, U> Default for TypedPoint2D<T, U> {
|
||||
fn default() -> Self {
|
||||
TypedPoint2D::new(Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedPoint2D<T, U> {
|
||||
/// Constructor taking scalar values directly.
|
||||
#[inline]
|
||||
|
@ -136,6 +142,11 @@ impl<T: Copy, U> TypedPoint2D<T, U> {
|
|||
pub fn to_array(&self) -> [T; 2] {
|
||||
[self.x, self.y]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_tuple(&self) -> (T, T) {
|
||||
(self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Add<T, Output = T>, U> TypedPoint2D<T, U> {
|
||||
|
@ -411,6 +422,18 @@ impl<T: Copy, U> From<[T; 2]> for TypedPoint2D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> Into<(T, T)> for TypedPoint2D<T, U> {
|
||||
fn into(self) -> (T, T) {
|
||||
self.to_tuple()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> From<(T, T)> for TypedPoint2D<T, U> {
|
||||
fn from(tuple: (T, T)) -> Self {
|
||||
point2(tuple.0, tuple.1)
|
||||
}
|
||||
}
|
||||
|
||||
/// A 3d Point tagged with a unit.
|
||||
#[derive(EuclidMatrix)]
|
||||
#[repr(C)]
|
||||
|
@ -435,6 +458,11 @@ impl<T: Copy + Zero, U> TypedPoint3D<T, U> {
|
|||
pub fn origin() -> Self {
|
||||
point3(Zero::zero(), Zero::zero(), Zero::zero())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn zero() -> Self {
|
||||
Self::origin()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + One, U> TypedPoint3D<T, U> {
|
||||
|
@ -442,6 +470,11 @@ impl<T: Copy + One, U> TypedPoint3D<T, U> {
|
|||
pub fn to_array_4d(&self) -> [T; 4] {
|
||||
[self.x, self.y, self.z, One::one()]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_tuple_4d(&self) -> (T, T, T, T) {
|
||||
(self.x, self.y, self.z, One::one())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedPoint3D<T, U>
|
||||
|
@ -474,6 +507,12 @@ impl<T: fmt::Display, U> fmt::Display for TypedPoint3D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Default, U> Default for TypedPoint3D<T, U> {
|
||||
fn default() -> Self {
|
||||
TypedPoint3D::new(Default::default(), Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> TypedPoint3D<T, U> {
|
||||
/// Constructor taking scalar values directly.
|
||||
#[inline]
|
||||
|
@ -541,6 +580,11 @@ impl<T: Copy, U> TypedPoint3D<T, U> {
|
|||
[self.x, self.y, self.z]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_tuple(&self) -> (T, T, T) {
|
||||
(self.x, self.y, self.z)
|
||||
}
|
||||
|
||||
/// Drop the units, preserving only the numeric value.
|
||||
#[inline]
|
||||
pub fn to_untyped(&self) -> Point3D<T> {
|
||||
|
@ -560,6 +604,13 @@ impl<T: Copy, U> TypedPoint3D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Add<T, Output = T>, U> TypedPoint3D<T, U> {
|
||||
#[inline]
|
||||
pub fn add_size(&self, other: &TypedSize3D<T, U>) -> Self {
|
||||
point3(self.x + other.width, self.y + other.height, self.z + other.depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Add<T, Output = T>, U> AddAssign<TypedVector3D<T, U>> for TypedPoint3D<T, U> {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, other: TypedVector3D<T, U>) {
|
||||
|
@ -606,6 +657,14 @@ impl<T: Copy + Mul<T, Output = T>, U> Mul<T> for TypedPoint3D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Mul<T, Output = T>, U1, U2> Mul<TypedScale<T, U1, U2>> for TypedPoint3D<T, U1> {
|
||||
type Output = TypedPoint3D<T, U2>;
|
||||
#[inline]
|
||||
fn mul(self, scale: TypedScale<T, U1, U2>) -> TypedPoint3D<T, U2> {
|
||||
point3(self.x * scale.get(), self.y * scale.get(), self.z * scale.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Div<T, Output = T>, U> Div<T> for TypedPoint3D<T, U> {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
|
@ -614,6 +673,14 @@ impl<T: Copy + Div<T, Output = T>, U> Div<T> for TypedPoint3D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Div<T, Output = T>, U1, U2> Div<TypedScale<T, U1, U2>> for TypedPoint3D<T, U2> {
|
||||
type Output = TypedPoint3D<T, U1>;
|
||||
#[inline]
|
||||
fn div(self, scale: TypedScale<T, U1, U2>) -> TypedPoint3D<T, U1> {
|
||||
point3(self.x / scale.get(), self.y / scale.get(), self.z / scale.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float, U> TypedPoint3D<T, U> {
|
||||
#[inline]
|
||||
pub fn min(self, other: Self) -> Self {
|
||||
|
@ -789,6 +856,18 @@ impl<T: Copy, U> From<[T; 3]> for TypedPoint3D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> Into<(T, T, T)> for TypedPoint3D<T, U> {
|
||||
fn into(self) -> (T, T, T) {
|
||||
self.to_tuple()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> From<(T, T, T)> for TypedPoint3D<T, U> {
|
||||
fn from(tuple: (T, T, T)) -> Self {
|
||||
point3(tuple.0, tuple.1, tuple.2)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn point2<T: Copy, U>(x: T, y: T) -> TypedPoint2D<T, U> {
|
||||
TypedPoint2D::new(x, y)
|
||||
}
|
||||
|
|
|
@ -11,10 +11,12 @@ use super::UnknownUnit;
|
|||
use length::Length;
|
||||
use scale::TypedScale;
|
||||
use num::*;
|
||||
use box2d::TypedBox2D;
|
||||
use point::TypedPoint2D;
|
||||
use vector::TypedVector2D;
|
||||
use side_offsets::TypedSideOffsets2D;
|
||||
use size::TypedSize2D;
|
||||
use approxord::{min, max};
|
||||
|
||||
use num_traits::NumCast;
|
||||
#[cfg(feature = "serde")]
|
||||
|
@ -93,6 +95,12 @@ impl<T: fmt::Display, U> fmt::Display for TypedRect<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Default, U> Default for TypedRect<T, U> {
|
||||
fn default() -> Self {
|
||||
TypedRect::new(Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedRect<T, U> {
|
||||
/// Constructor.
|
||||
pub fn new(origin: TypedPoint2D<T, U>, size: TypedSize2D<T, U>) -> Self {
|
||||
|
@ -256,6 +264,14 @@ where
|
|||
TypedPoint2D::new(self.max_x(), self.max_y())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_box2d(&self) -> TypedBox2D<T, U> {
|
||||
TypedBox2D {
|
||||
min: self.origin,
|
||||
max: self.bottom_right(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn translate_by_size(&self, size: &TypedSize2D<T, U>) -> Self {
|
||||
|
@ -428,22 +444,6 @@ impl<T: Copy + PartialEq + Zero, U> TypedRect<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn min<T: Clone + PartialOrd>(x: T, y: T) -> T {
|
||||
if x <= y {
|
||||
x
|
||||
} else {
|
||||
y
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max<T: Clone + PartialOrd>(x: T, y: T) -> T {
|
||||
if x >= y {
|
||||
x
|
||||
} else {
|
||||
y
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Mul<T, Output = T>, U> Mul<T> for TypedRect<T, U> {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
|
@ -623,15 +623,6 @@ mod tests {
|
|||
use size::Size2D;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_min_max() {
|
||||
assert!(min(0u32, 1u32) == 0u32);
|
||||
assert!(min(-1.0f32, 0.0f32) == -1.0f32);
|
||||
|
||||
assert!(max(0u32, 1u32) == 1u32);
|
||||
assert!(max(-1.0f32, 0.0f32) == 0.0f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_translate() {
|
||||
let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
use approxeq::ApproxEq;
|
||||
use num_traits::Float;
|
||||
use trig::Trig;
|
||||
use {TypedRotation3D, TypedTransform3D, TypedVector3D, UnknownUnit};
|
||||
|
||||
/// A rigid transformation. All lengths are preserved under such a transformation.
|
||||
///
|
||||
///
|
||||
/// Internally, this is a rotation and a translation, with the rotation
|
||||
/// applied first (i.e. `Rotation * Translation`, in row-vector notation)
|
||||
///
|
||||
/// This can be more efficient to use over full matrices, especially if you
|
||||
/// have to deal with the decomposed quantities often.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[repr(C)]
|
||||
pub struct TypedRigidTransform3D<T, Src, Dst> {
|
||||
pub rotation: TypedRotation3D<T, Src, Dst>,
|
||||
pub translation: TypedVector3D<T, Dst>,
|
||||
}
|
||||
|
||||
pub type RigidTransform3D<T> = TypedRigidTransform3D<T, UnknownUnit, UnknownUnit>;
|
||||
|
||||
// All matrix multiplication in this file is in row-vector notation,
|
||||
// i.e. a vector `v` is transformed with `v * T`, and if you want to apply `T1`
|
||||
// before `T2` you use `T1 * T2`
|
||||
|
||||
impl<T: Float + ApproxEq<T>, Src, Dst> TypedRigidTransform3D<T, Src, Dst> {
|
||||
/// Construct a new rigid transformation, where the `rotation` applies first
|
||||
#[inline]
|
||||
pub fn new(rotation: TypedRotation3D<T, Src, Dst>, translation: TypedVector3D<T, Dst>) -> Self {
|
||||
Self {
|
||||
rotation,
|
||||
translation,
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct an identity transform
|
||||
#[inline]
|
||||
pub fn identity() -> Self {
|
||||
Self {
|
||||
rotation: TypedRotation3D::identity(),
|
||||
translation: TypedVector3D::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a new rigid transformation, where the `translation` applies first
|
||||
#[inline]
|
||||
pub fn new_from_reversed(
|
||||
translation: TypedVector3D<T, Src>,
|
||||
rotation: TypedRotation3D<T, Src, Dst>,
|
||||
) -> Self {
|
||||
// T * R
|
||||
// = (R * R^-1) * T * R
|
||||
// = R * (R^-1 * T * R)
|
||||
// = R * T'
|
||||
//
|
||||
// T' = (R^-1 * T * R) is also a translation matrix
|
||||
// It is equivalent to the translation matrix obtained by rotating the
|
||||
// translation by R
|
||||
|
||||
let translation = rotation.rotate_vector3d(&translation);
|
||||
Self {
|
||||
rotation,
|
||||
translation,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_rotation(rotation: TypedRotation3D<T, Src, Dst>) -> Self {
|
||||
Self {
|
||||
rotation,
|
||||
translation: TypedVector3D::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_translation(translation: TypedVector3D<T, Dst>) -> Self {
|
||||
Self {
|
||||
translation,
|
||||
rotation: TypedRotation3D::identity(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Decompose this into a translation and an rotation to be applied in the opposite order
|
||||
///
|
||||
/// i.e., the translation is applied _first_
|
||||
#[inline]
|
||||
pub fn decompose_reversed(&self) -> (TypedVector3D<T, Src>, TypedRotation3D<T, Src, Dst>) {
|
||||
// self = R * T
|
||||
// = R * T * (R^-1 * R)
|
||||
// = (R * T * R^-1) * R)
|
||||
// = T' * R
|
||||
//
|
||||
// T' = (R^ * T * R^-1) is T rotated by R^-1
|
||||
|
||||
let translation = self.rotation.inverse().rotate_vector3d(&self.translation);
|
||||
(translation, self.rotation)
|
||||
}
|
||||
|
||||
/// Returns the multiplication of the two transforms such that
|
||||
/// other's transformation applies after self's transformation.
|
||||
///
|
||||
/// i.e., this produces `self * other` in row-vector notation
|
||||
#[inline]
|
||||
pub fn post_mul<Dst2>(
|
||||
&self,
|
||||
other: &TypedRigidTransform3D<T, Dst, Dst2>,
|
||||
) -> TypedRigidTransform3D<T, Src, Dst2> {
|
||||
// self = R1 * T1
|
||||
// other = R2 * T2
|
||||
// result = R1 * T1 * R2 * T2
|
||||
// = R1 * (R2 * R2^-1) * T1 * R2 * T2
|
||||
// = (R1 * R2) * (R2^-1 * T1 * R2) * T2
|
||||
// = R' * T' * T2
|
||||
// = R' * T''
|
||||
//
|
||||
// (R2^-1 * T2 * R2^) = T' = T2 rotated by R2
|
||||
// R1 * R2 = R'
|
||||
// T' * T2 = T'' = vector addition of translations T2 and T'
|
||||
|
||||
let t_prime = other
|
||||
.rotation
|
||||
.rotate_vector3d(&self.translation);
|
||||
let r_prime = self.rotation.post_rotate(&other.rotation);
|
||||
let t_prime2 = t_prime + other.translation;
|
||||
TypedRigidTransform3D {
|
||||
rotation: r_prime,
|
||||
translation: t_prime2,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the multiplication of the two transforms such that
|
||||
/// self's transformation applies after other's transformation.
|
||||
///
|
||||
/// i.e., this produces `other * self` in row-vector notation
|
||||
#[inline]
|
||||
pub fn pre_mul<Src2>(
|
||||
&self,
|
||||
other: &TypedRigidTransform3D<T, Src2, Src>,
|
||||
) -> TypedRigidTransform3D<T, Src2, Dst> {
|
||||
other.post_mul(&self)
|
||||
}
|
||||
|
||||
/// Inverts the transformation
|
||||
#[inline]
|
||||
pub fn inverse(&self) -> TypedRigidTransform3D<T, Dst, Src> {
|
||||
// result = (self)^-1
|
||||
// = (R * T)^-1
|
||||
// = T^-1 * R^-1
|
||||
// = (R^-1 * R) * T^-1 * R^-1
|
||||
// = R^-1 * (R * T^-1 * R^-1)
|
||||
// = R' * T'
|
||||
//
|
||||
// T' = (R * T^-1 * R^-1) = (-T) rotated by R^-1
|
||||
// R' = R^-1
|
||||
//
|
||||
// An easier way of writing this is to use new_from_reversed() with R^-1 and T^-1
|
||||
|
||||
TypedRigidTransform3D::new_from_reversed(
|
||||
-self.translation,
|
||||
self.rotation.inverse(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_transform(&self) -> TypedTransform3D<T, Src, Dst>
|
||||
where
|
||||
T: Trig,
|
||||
{
|
||||
self.translation
|
||||
.to_transform()
|
||||
.pre_mul(&self.rotation.to_transform())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float + ApproxEq<T>, Src, Dst> From<TypedRotation3D<T, Src, Dst>>
|
||||
for TypedRigidTransform3D<T, Src, Dst>
|
||||
{
|
||||
fn from(rot: TypedRotation3D<T, Src, Dst>) -> Self {
|
||||
Self::from_rotation(rot)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float + ApproxEq<T>, Src, Dst> From<TypedVector3D<T, Dst>>
|
||||
for TypedRigidTransform3D<T, Src, Dst>
|
||||
{
|
||||
fn from(t: TypedVector3D<T, Dst>) -> Self {
|
||||
Self::from_translation(t)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::RigidTransform3D;
|
||||
use {Rotation3D, TypedTransform3D, Vector3D};
|
||||
|
||||
#[test]
|
||||
fn test_rigid_construction() {
|
||||
let translation = Vector3D::new(12.1, 17.8, -5.5);
|
||||
let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);
|
||||
|
||||
let rigid = RigidTransform3D::new(rotation, translation);
|
||||
assert!(rigid
|
||||
.to_transform()
|
||||
.approx_eq(&translation.to_transform().pre_mul(&rotation.to_transform())));
|
||||
|
||||
let rigid = RigidTransform3D::new_from_reversed(translation, rotation);
|
||||
assert!(rigid.to_transform().approx_eq(
|
||||
&translation
|
||||
.to_transform()
|
||||
.post_mul(&rotation.to_transform())
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rigid_decomposition() {
|
||||
let translation = Vector3D::new(12.1, 17.8, -5.5);
|
||||
let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);
|
||||
|
||||
let rigid = RigidTransform3D::new(rotation, translation);
|
||||
let (t2, r2) = rigid.decompose_reversed();
|
||||
assert!(rigid
|
||||
.to_transform()
|
||||
.approx_eq(&t2.to_transform().post_mul(&r2.to_transform())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rigid_inverse() {
|
||||
let translation = Vector3D::new(12.1, 17.8, -5.5);
|
||||
let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);
|
||||
|
||||
let rigid = RigidTransform3D::new(rotation, translation);
|
||||
let inverse = rigid.inverse();
|
||||
assert!(rigid
|
||||
.post_mul(&inverse)
|
||||
.to_transform()
|
||||
.approx_eq(&TypedTransform3D::identity()));
|
||||
assert!(inverse
|
||||
.to_transform()
|
||||
.approx_eq(&rigid.to_transform().inverse().unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rigid_multiply() {
|
||||
let translation = Vector3D::new(12.1, 17.8, -5.5);
|
||||
let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);
|
||||
let translation2 = Vector3D::new(9.3, -3.9, 1.1);
|
||||
let rotation2 = Rotation3D::unit_quaternion(0.1, 0.2, 0.3, -0.4);
|
||||
let rigid = RigidTransform3D::new(rotation, translation);
|
||||
let rigid2 = RigidTransform3D::new(rotation2, translation2);
|
||||
|
||||
assert!(rigid
|
||||
.post_mul(&rigid2)
|
||||
.to_transform()
|
||||
.approx_eq(&rigid.to_transform().post_mul(&rigid2.to_transform())));
|
||||
assert!(rigid
|
||||
.pre_mul(&rigid2)
|
||||
.to_transform()
|
||||
.approx_eq(&rigid.to_transform().pre_mul(&rigid2.to_transform())));
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use approxeq::ApproxEq;
|
||||
use num_traits::{Float, FloatConst, One, Zero};
|
||||
use num_traits::{Float, FloatConst, One, Zero, NumCast};
|
||||
use core::fmt;
|
||||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign};
|
||||
use core::marker::PhantomData;
|
||||
|
@ -475,8 +475,8 @@ where
|
|||
where
|
||||
T: ApproxEq<T>,
|
||||
{
|
||||
// TODO: we might need to relax the threshold here, because of floating point imprecision.
|
||||
self.square_norm().approx_eq(&T::one())
|
||||
let eps = NumCast::from(1.0e-5).unwrap();
|
||||
self.square_norm().approx_eq_eps(&T::one(), &eps)
|
||||
}
|
||||
|
||||
/// Spherical linear interpolation between this rotation and another rotation.
|
||||
|
@ -560,7 +560,7 @@ where
|
|||
self.rotate_point3d(&point.to_3d()).xy()
|
||||
}
|
||||
|
||||
/// Returns the given 3d vector transformed by this rotation then projected on the xy plane.
|
||||
/// Returns the given 3d vector transformed by this rotation.
|
||||
///
|
||||
/// The input vector must be use the unit Src, and the returned point has the unit Dst.
|
||||
#[inline]
|
||||
|
|
|
@ -17,7 +17,7 @@ use core::fmt;
|
|||
use core::ops::Add;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
|
||||
/// A group of 2D side offsets, which correspond to top/left/bottom/right for borders, padding,
|
||||
/// and margins in CSS, optionally tagged with a unit.
|
||||
#[derive(EuclidMatrix)]
|
||||
#[repr(C)]
|
||||
|
@ -40,7 +40,19 @@ impl<T: fmt::Debug, U> fmt::Debug for TypedSideOffsets2D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The default side offset type with no unit.
|
||||
impl<T: Default, U> Default for TypedSideOffsets2D<T, U> {
|
||||
fn default() -> Self {
|
||||
TypedSideOffsets2D {
|
||||
top: Default::default(),
|
||||
right: Default::default(),
|
||||
bottom: Default::default(),
|
||||
left: Default::default(),
|
||||
_unit: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default 2D side offset type with no unit.
|
||||
pub type SideOffsets2D<T> = TypedSideOffsets2D<T, UnknownUnit>;
|
||||
|
||||
impl<T: Copy, U> TypedSideOffsets2D<T, U> {
|
||||
|
|
|
@ -13,6 +13,7 @@ use mint;
|
|||
use length::Length;
|
||||
use scale::TypedScale;
|
||||
use vector::{TypedVector2D, vec2, BoolVector2D};
|
||||
use vector::{TypedVector3D, vec3, BoolVector3D};
|
||||
use num::*;
|
||||
|
||||
use num_traits::{Float, NumCast, Signed};
|
||||
|
@ -47,6 +48,12 @@ impl<T: fmt::Display, U> fmt::Display for TypedSize2D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Default, U> Default for TypedSize2D<T, U> {
|
||||
fn default() -> Self {
|
||||
TypedSize2D::new(Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedSize2D<T, U> {
|
||||
/// Constructor taking scalar values.
|
||||
pub fn new(width: T, height: T) -> Self {
|
||||
|
@ -198,6 +205,11 @@ impl<T: Copy, U> TypedSize2D<T, U> {
|
|||
[self.width, self.height]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_tuple(&self) -> (T, T) {
|
||||
(self.width, self.height)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_vector(&self) -> TypedVector2D<T, U> {
|
||||
vec2(self.width, self.height)
|
||||
|
@ -380,6 +392,29 @@ impl<T, U> Into<mint::Vector2<T>> for TypedSize2D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> Into<[T; 2]> for TypedSize2D<T, U> {
|
||||
fn into(self) -> [T; 2] {
|
||||
self.to_array()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> From<[T; 2]> for TypedSize2D<T, U> {
|
||||
fn from(array: [T; 2]) -> Self {
|
||||
size2(array[0], array[1])
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> Into<(T, T)> for TypedSize2D<T, U> {
|
||||
fn into(self) -> (T, T) {
|
||||
self.to_tuple()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> From<(T, T)> for TypedSize2D<T, U> {
|
||||
fn from(tuple: (T, T)) -> Self {
|
||||
size2(tuple.0, tuple.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod size2d {
|
||||
|
@ -441,3 +476,386 @@ mod size2d {
|
|||
assert_eq!(s1, s2);
|
||||
}
|
||||
}
|
||||
|
||||
/// A 3d size tagged with a unit.
|
||||
#[derive(EuclidMatrix)]
|
||||
#[repr(C)]
|
||||
pub struct TypedSize3D<T, U> {
|
||||
pub width: T,
|
||||
pub height: T,
|
||||
pub depth: T,
|
||||
#[doc(hidden)]
|
||||
pub _unit: PhantomData<U>,
|
||||
}
|
||||
|
||||
/// Default 3d size type with no unit.
|
||||
///
|
||||
/// `Size3D` provides the same methods as `TypedSize3D`.
|
||||
pub type Size3D<T> = TypedSize3D<T, UnknownUnit>;
|
||||
|
||||
impl<T: fmt::Debug, U> fmt::Debug for TypedSize3D<T, U> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}×{:?}×{:?}", self.width, self.height, self.depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display, U> fmt::Display for TypedSize3D<T, U> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "({}x{}x{})", self.width, self.height, self.depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default, U> Default for TypedSize3D<T, U> {
|
||||
fn default() -> Self {
|
||||
TypedSize3D::new(Default::default(), Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedSize3D<T, U> {
|
||||
/// Constructor taking scalar values.
|
||||
pub fn new(width: T, height: T, depth: T) -> Self {
|
||||
TypedSize3D {
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
_unit: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone, U> TypedSize3D<T, U> {
|
||||
/// Constructor taking scalar strongly typed lengths.
|
||||
pub fn from_lengths(width: Length<T, U>, height: Length<T, U>, depth: Length<T, U>) -> Self {
|
||||
TypedSize3D::new(width.get(), height.get(), depth.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Round, U> TypedSize3D<T, U> {
|
||||
/// Rounds each component to the nearest integer value.
|
||||
///
|
||||
/// This behavior is preserved for negative values (unlike the basic cast).
|
||||
pub fn round(&self) -> Self {
|
||||
TypedSize3D::new(self.width.round(), self.height.round(), self.depth.round())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ceil, U> TypedSize3D<T, U> {
|
||||
/// Rounds each component to the smallest integer equal or greater than the original value.
|
||||
///
|
||||
/// This behavior is preserved for negative values (unlike the basic cast).
|
||||
pub fn ceil(&self) -> Self {
|
||||
TypedSize3D::new(self.width.ceil(), self.height.ceil(), self.depth.ceil())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Floor, U> TypedSize3D<T, U> {
|
||||
/// Rounds each component to the biggest integer equal or lower than the original value.
|
||||
///
|
||||
/// This behavior is preserved for negative values (unlike the basic cast).
|
||||
pub fn floor(&self) -> Self {
|
||||
TypedSize3D::new(self.width.floor(), self.height.floor(), self.depth.floor())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Add<T, Output = T>, U> Add for TypedSize3D<T, U> {
|
||||
type Output = Self;
|
||||
fn add(self, other: Self) -> Self {
|
||||
TypedSize3D::new(self.width + other.width, self.height + other.height, self.depth + other.depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Sub<T, Output = T>, U> Sub for TypedSize3D<T, U> {
|
||||
type Output = Self;
|
||||
fn sub(self, other: Self) -> Self {
|
||||
TypedSize3D::new(self.width - other.width, self.height - other.height, self.depth - other.depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Clone + Mul<T, Output=T>, U> TypedSize3D<T, U> {
|
||||
pub fn volume(&self) -> T {
|
||||
self.width * self.height * self.depth
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedSize3D<T, U>
|
||||
where
|
||||
T: Copy + One + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
|
||||
{
|
||||
/// Linearly interpolate between this size and another size.
|
||||
///
|
||||
/// `t` is expected to be between zero and one.
|
||||
#[inline]
|
||||
pub fn lerp(&self, other: Self, t: T) -> Self {
|
||||
let one_t = T::one() - t;
|
||||
size3(
|
||||
one_t * self.width + t * other.width,
|
||||
one_t * self.height + t * other.height,
|
||||
one_t * self.depth + t * other.depth,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zero + PartialOrd, U> TypedSize3D<T, U> {
|
||||
pub fn is_empty_or_negative(&self) -> bool {
|
||||
let zero = T::zero();
|
||||
self.width <= zero || self.height <= zero || self.depth <= zero
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zero, U> TypedSize3D<T, U> {
|
||||
pub fn zero() -> Self {
|
||||
TypedSize3D::new(Zero::zero(), Zero::zero(), Zero::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zero, U> Zero for TypedSize3D<T, U> {
|
||||
fn zero() -> Self {
|
||||
TypedSize3D::new(Zero::zero(), Zero::zero(), Zero::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Mul<T, Output = T>, U> Mul<T> for TypedSize3D<T, U> {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn mul(self, scale: T) -> Self {
|
||||
TypedSize3D::new(self.width * scale, self.height * scale, self.depth * scale)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Div<T, Output = T>, U> Div<T> for TypedSize3D<T, U> {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn div(self, scale: T) -> Self {
|
||||
TypedSize3D::new(self.width / scale, self.height / scale, self.depth / scale)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Mul<T, Output = T>, U1, U2> Mul<TypedScale<T, U1, U2>> for TypedSize3D<T, U1> {
|
||||
type Output = TypedSize3D<T, U2>;
|
||||
#[inline]
|
||||
fn mul(self, scale: TypedScale<T, U1, U2>) -> TypedSize3D<T, U2> {
|
||||
TypedSize3D::new(self.width * scale.get(), self.height * scale.get(), self.depth * scale.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Div<T, Output = T>, U1, U2> Div<TypedScale<T, U1, U2>> for TypedSize3D<T, U2> {
|
||||
type Output = TypedSize3D<T, U1>;
|
||||
#[inline]
|
||||
fn div(self, scale: TypedScale<T, U1, U2>) -> TypedSize3D<T, U1> {
|
||||
TypedSize3D::new(self.width / scale.get(), self.height / scale.get(), self.depth / scale.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> TypedSize3D<T, U> {
|
||||
/// Returns self.width as a Length carrying the unit.
|
||||
#[inline]
|
||||
pub fn width_typed(&self) -> Length<T, U> {
|
||||
Length::new(self.width)
|
||||
}
|
||||
|
||||
/// Returns self.height as a Length carrying the unit.
|
||||
#[inline]
|
||||
pub fn height_typed(&self) -> Length<T, U> {
|
||||
Length::new(self.height)
|
||||
}
|
||||
|
||||
/// Returns self.depth as a Length carrying the unit.
|
||||
#[inline]
|
||||
pub fn depth_typed(&self) -> Length<T, U> {
|
||||
Length::new(self.depth)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_array(&self) -> [T; 3] {
|
||||
[self.width, self.height, self.depth]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_vector(&self) -> TypedVector3D<T, U> {
|
||||
vec3(self.width, self.height, self.depth)
|
||||
}
|
||||
|
||||
/// Drop the units, preserving only the numeric value.
|
||||
pub fn to_untyped(&self) -> Size3D<T> {
|
||||
TypedSize3D::new(self.width, self.height, self.depth)
|
||||
}
|
||||
|
||||
/// Tag a unitless value with units.
|
||||
pub fn from_untyped(p: &Size3D<T>) -> Self {
|
||||
TypedSize3D::new(p.width, p.height, p.depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NumCast + Copy, Unit> TypedSize3D<T, Unit> {
|
||||
/// Cast from one numeric representation to another, preserving the units.
|
||||
///
|
||||
/// When casting from floating point to integer coordinates, the decimals are truncated
|
||||
/// as one would expect from a simple cast, but this behavior does not always make sense
|
||||
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
|
||||
pub fn cast<NewT: NumCast + Copy>(&self) -> TypedSize3D<NewT, Unit> {
|
||||
self.try_cast().unwrap()
|
||||
}
|
||||
|
||||
/// Fallible cast from one numeric representation to another, preserving the units.
|
||||
///
|
||||
/// When casting from floating point to integer coordinates, the decimals are truncated
|
||||
/// as one would expect from a simple cast, but this behavior does not always make sense
|
||||
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
|
||||
pub fn try_cast<NewT: NumCast + Copy>(&self) -> Option<TypedSize3D<NewT, Unit>> {
|
||||
match (NumCast::from(self.width), NumCast::from(self.height), NumCast::from(self.depth)) {
|
||||
(Some(w), Some(h), Some(d)) => Some(TypedSize3D::new(w, h, d)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience functions for common casts
|
||||
|
||||
/// Cast into an `f32` size.
|
||||
pub fn to_f32(&self) -> TypedSize3D<f32, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `f64` size.
|
||||
pub fn to_f64(&self) -> TypedSize3D<f64, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `uint` size, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point sizes, it is worth considering whether
|
||||
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
|
||||
/// the desired conversion behavior.
|
||||
pub fn to_usize(&self) -> TypedSize3D<usize, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `u32` size, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point sizes, it is worth considering whether
|
||||
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
|
||||
/// the desired conversion behavior.
|
||||
pub fn to_u32(&self) -> TypedSize3D<u32, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `i32` size, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point sizes, it is worth considering whether
|
||||
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
|
||||
/// the desired conversion behavior.
|
||||
pub fn to_i32(&self) -> TypedSize3D<i32, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
|
||||
/// Cast into an `i64` size, truncating decimals if any.
|
||||
///
|
||||
/// When casting from floating point sizes, it is worth considering whether
|
||||
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
|
||||
/// the desired conversion behavior.
|
||||
pub fn to_i64(&self) -> TypedSize3D<i64, Unit> {
|
||||
self.cast()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedSize3D<T, U>
|
||||
where
|
||||
T: Signed,
|
||||
{
|
||||
pub fn abs(&self) -> Self {
|
||||
size3(self.width.abs(), self.height.abs(), self.depth.abs())
|
||||
}
|
||||
|
||||
pub fn is_positive(&self) -> bool {
|
||||
self.width.is_positive() && self.height.is_positive() && self.depth.is_positive()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialOrd, U> TypedSize3D<T, U> {
|
||||
pub fn greater_than(&self, other: &Self) -> BoolVector3D {
|
||||
BoolVector3D {
|
||||
x: self.width > other.width,
|
||||
y: self.height > other.height,
|
||||
z: self.depth > other.depth,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lower_than(&self, other: &Self) -> BoolVector3D {
|
||||
BoolVector3D {
|
||||
x: self.width < other.width,
|
||||
y: self.height < other.height,
|
||||
z: self.depth < other.depth,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: PartialEq, U> TypedSize3D<T, U> {
|
||||
pub fn equal(&self, other: &Self) -> BoolVector3D {
|
||||
BoolVector3D {
|
||||
x: self.width == other.width,
|
||||
y: self.height == other.height,
|
||||
z: self.depth == other.depth,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not_equal(&self, other: &Self) -> BoolVector3D {
|
||||
BoolVector3D {
|
||||
x: self.width != other.width,
|
||||
y: self.height != other.height,
|
||||
z: self.depth != other.depth,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Float, U> TypedSize3D<T, U> {
|
||||
#[inline]
|
||||
pub fn min(self, other: Self) -> Self {
|
||||
size3(
|
||||
self.width.min(other.width),
|
||||
self.height.min(other.height),
|
||||
self.depth.min(other.depth),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn max(self, other: Self) -> Self {
|
||||
size3(
|
||||
self.width.max(other.width),
|
||||
self.height.max(other.height),
|
||||
self.depth.max(other.depth),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn clamp(&self, start: Self, end: Self) -> Self {
|
||||
self.max(start).min(end)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Shorthand for `TypedSize3D::new(w, h, d)`.
|
||||
pub fn size3<T, U>(w: T, h: T, d: T) -> TypedSize3D<T, U> {
|
||||
TypedSize3D::new(w, h, d)
|
||||
}
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
impl<T, U> From<mint::Vector3<T>> for TypedSize3D<T, U> {
|
||||
fn from(v: mint::Vector3<T>) -> Self {
|
||||
TypedSize3D {
|
||||
width: v.x,
|
||||
height: v.y,
|
||||
depth: v.z,
|
||||
_unit: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "mint")]
|
||||
impl<T, U> Into<mint::Vector3<T>> for TypedSize3D<T, U> {
|
||||
fn into(self) -> mint::Vector3<T> {
|
||||
mint::Vector3 {
|
||||
x: self.width,
|
||||
y: self.height,
|
||||
z: self.depth,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,10 @@ use num_traits::NumCast;
|
|||
/// A pre-transformation corresponds to adding an operation that is applied before
|
||||
/// the rest of the transformation, while a post-transformation adds an operation
|
||||
/// that is applied after.
|
||||
///
|
||||
/// These transforms are for working with _row vectors_, so the matrix math for transforming
|
||||
/// a vector is `v * T`. If your library is using column vectors, use `row_major` functions when you
|
||||
/// are asked for `column_major` representations and vice versa.
|
||||
#[repr(C)]
|
||||
#[derive(EuclidMatrix)]
|
||||
pub struct TypedTransform2D<T, Src, Dst> {
|
||||
|
@ -50,6 +54,10 @@ pub type Transform2D<T> = TypedTransform2D<T, UnknownUnit, UnknownUnit>;
|
|||
|
||||
impl<T: Copy, Src, Dst> TypedTransform2D<T, Src, Dst> {
|
||||
/// Create a transform specifying its matrix elements in row-major order.
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), then please use `column_major`
|
||||
pub fn row_major(m11: T, m12: T, m21: T, m22: T, m31: T, m32: T) -> Self {
|
||||
TypedTransform2D {
|
||||
m11, m12,
|
||||
|
@ -60,6 +68,10 @@ impl<T: Copy, Src, Dst> TypedTransform2D<T, Src, Dst> {
|
|||
}
|
||||
|
||||
/// Create a transform specifying its matrix elements in column-major order.
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), then please use `row_major`
|
||||
pub fn column_major(m11: T, m21: T, m31: T, m12: T, m22: T, m32: T) -> Self {
|
||||
TypedTransform2D {
|
||||
m11, m12,
|
||||
|
@ -71,6 +83,10 @@ impl<T: Copy, Src, Dst> TypedTransform2D<T, Src, Dst> {
|
|||
|
||||
/// Returns an array containing this transform's terms in row-major order (the order
|
||||
/// in which the transform is actually laid out in memory).
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), then please use `to_column_major_array`
|
||||
pub fn to_row_major_array(&self) -> [T; 6] {
|
||||
[
|
||||
self.m11, self.m12,
|
||||
|
@ -80,6 +96,10 @@ impl<T: Copy, Src, Dst> TypedTransform2D<T, Src, Dst> {
|
|||
}
|
||||
|
||||
/// Returns an array containing this transform's terms in column-major order.
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), then please use `to_row_major_array`
|
||||
pub fn to_column_major_array(&self) -> [T; 6] {
|
||||
[
|
||||
self.m11, self.m21, self.m31,
|
||||
|
@ -91,6 +111,10 @@ impl<T: Copy, Src, Dst> TypedTransform2D<T, Src, Dst> {
|
|||
/// as arrays.
|
||||
///
|
||||
/// This is a convenience method to interface with other libraries like glium.
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), this will return column major arrays.
|
||||
pub fn to_row_arrays(&self) -> [[T; 2]; 3] {
|
||||
[
|
||||
[self.m11, self.m12],
|
||||
|
@ -100,6 +124,10 @@ impl<T: Copy, Src, Dst> TypedTransform2D<T, Src, Dst> {
|
|||
}
|
||||
|
||||
/// Creates a transform from an array of 6 elements in row-major order.
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), please provide a column major array.
|
||||
pub fn from_row_major_array(array: [T; 6]) -> Self {
|
||||
Self::row_major(
|
||||
array[0], array[1],
|
||||
|
@ -109,6 +137,10 @@ impl<T: Copy, Src, Dst> TypedTransform2D<T, Src, Dst> {
|
|||
}
|
||||
|
||||
/// Creates a transform from 3 rows of 2 elements (row-major order).
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), please provide a column major array.
|
||||
pub fn from_row_arrays(array: [[T; 2]; 3]) -> Self {
|
||||
Self::row_major(
|
||||
array[0][0], array[0][1],
|
||||
|
@ -194,6 +226,8 @@ where T: Copy + Clone +
|
|||
|
||||
/// Returns the multiplication of the two matrices such that mat's transformation
|
||||
/// applies after self's transformation.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to self * mat
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn post_mul<NewDst>(&self, mat: &TypedTransform2D<T, Dst, NewDst>) -> TypedTransform2D<T, Src, NewDst> {
|
||||
TypedTransform2D::row_major(
|
||||
|
@ -208,6 +242,8 @@ where T: Copy + Clone +
|
|||
|
||||
/// Returns the multiplication of the two matrices such that mat's transformation
|
||||
/// applies before self's transformation.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to mat * self
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn pre_mul<NewSrc>(&self, mat: &TypedTransform2D<T, NewSrc, Src>) -> TypedTransform2D<T, NewSrc, Dst> {
|
||||
mat.post_mul(self)
|
||||
|
@ -286,6 +322,8 @@ where T: Copy + Clone +
|
|||
}
|
||||
|
||||
/// Returns the given point transformed by this transform.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to `p * self`
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn transform_point(&self, point: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
|
||||
|
@ -294,6 +332,8 @@ where T: Copy + Clone +
|
|||
}
|
||||
|
||||
/// Returns the given vector transformed by this matrix.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to `v * self`
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "unstable", must_use)]
|
||||
pub fn transform_vector(&self, vec: &TypedVector2D<T, Src>) -> TypedVector2D<T, Dst> {
|
||||
|
|
|
@ -37,6 +37,10 @@ use num_traits::NumCast;
|
|||
/// A pre-transformation corresponds to adding an operation that is applied before
|
||||
/// the rest of the transformation, while a post-transformation adds an operation
|
||||
/// that is applied after.
|
||||
///
|
||||
/// These transforms are for working with _row vectors_, so the matrix math for transforming
|
||||
/// a vector is `v * T`. If your library is using column vectors, use `row_major` functions when you
|
||||
/// are asked for `column_major` representations and vice versa.
|
||||
#[derive(EuclidMatrix)]
|
||||
#[repr(C)]
|
||||
pub struct TypedTransform3D<T, Src, Dst> {
|
||||
|
@ -56,6 +60,10 @@ impl<T, Src, Dst> TypedTransform3D<T, Src, Dst> {
|
|||
///
|
||||
/// For example, the translation terms m41, m42, m43 on the last row with the
|
||||
/// row-major convention) are the 13rd, 14th and 15th parameters.
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), then please use `column_major`
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
pub fn row_major(
|
||||
|
@ -77,6 +85,10 @@ impl<T, Src, Dst> TypedTransform3D<T, Src, Dst> {
|
|||
///
|
||||
/// For example, the translation terms m41, m42, m43 on the last column with the
|
||||
/// column-major convention) are the 4th, 8th and 12nd parameters.
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), then please use `row_major`
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
pub fn column_major(
|
||||
|
@ -256,6 +268,8 @@ where T: Copy + Clone +
|
|||
|
||||
/// Returns the multiplication of the two matrices such that mat's transformation
|
||||
/// applies after self's transformation.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to self * mat
|
||||
pub fn post_mul<NewDst>(&self, mat: &TypedTransform3D<T, Dst, NewDst>) -> TypedTransform3D<T, Src, NewDst> {
|
||||
TypedTransform3D::row_major(
|
||||
self.m11 * mat.m11 + self.m12 * mat.m21 + self.m13 * mat.m31 + self.m14 * mat.m41,
|
||||
|
@ -279,6 +293,8 @@ where T: Copy + Clone +
|
|||
|
||||
/// Returns the multiplication of the two matrices such that mat's transformation
|
||||
/// applies before self's transformation.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to mat * self
|
||||
pub fn pre_mul<NewSrc>(&self, mat: &TypedTransform3D<T, NewSrc, Src>) -> TypedTransform3D<T, NewSrc, Dst> {
|
||||
mat.post_mul(self)
|
||||
}
|
||||
|
@ -410,6 +426,8 @@ where T: Copy + Clone +
|
|||
/// Returns the homogeneous vector corresponding to the transformed 2d point.
|
||||
///
|
||||
/// The input point must be use the unit Src, and the returned point has the unit Dst.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to `p * self`
|
||||
#[inline]
|
||||
pub fn transform_point2d_homogeneous(
|
||||
&self, p: &TypedPoint2D<T, Src>
|
||||
|
@ -427,6 +445,7 @@ where T: Copy + Clone +
|
|||
///
|
||||
/// The input point must be use the unit Src, and the returned point has the unit Dst.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to `p * self`
|
||||
#[inline]
|
||||
pub fn transform_point2d(&self, p: &TypedPoint2D<T, Src>) -> Option<TypedPoint2D<T, Dst>> {
|
||||
//Note: could use `transform_point2d_homogeneous()` but it would waste the calculus of `z`
|
||||
|
@ -444,6 +463,8 @@ where T: Copy + Clone +
|
|||
/// Returns the given 2d vector transformed by this matrix.
|
||||
///
|
||||
/// The input point must be use the unit Src, and the returned point has the unit Dst.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to `v * self`
|
||||
#[inline]
|
||||
pub fn transform_vector2d(&self, v: &TypedVector2D<T, Src>) -> TypedVector2D<T, Dst> {
|
||||
vec2(
|
||||
|
@ -455,6 +476,8 @@ where T: Copy + Clone +
|
|||
/// Returns the homogeneous vector corresponding to the transformed 3d point.
|
||||
///
|
||||
/// The input point must be use the unit Src, and the returned point has the unit Dst.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to `p * self`
|
||||
#[inline]
|
||||
pub fn transform_point3d_homogeneous(
|
||||
&self, p: &TypedPoint3D<T, Src>
|
||||
|
@ -471,6 +494,8 @@ where T: Copy + Clone +
|
|||
/// or `None` otherwise.
|
||||
///
|
||||
/// The input point must be use the unit Src, and the returned point has the unit Dst.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to `p * self`
|
||||
#[inline]
|
||||
pub fn transform_point3d(&self, p: &TypedPoint3D<T, Src>) -> Option<TypedPoint3D<T, Dst>> {
|
||||
self.transform_point3d_homogeneous(p).to_point3d()
|
||||
|
@ -479,6 +504,8 @@ where T: Copy + Clone +
|
|||
/// Returns the given 3d vector transformed by this matrix.
|
||||
///
|
||||
/// The input point must be use the unit Src, and the returned point has the unit Dst.
|
||||
///
|
||||
/// Assuming row vectors, this is equivalent to `v * self`
|
||||
#[inline]
|
||||
pub fn transform_vector3d(&self, v: &TypedVector3D<T, Src>) -> TypedVector3D<T, Dst> {
|
||||
vec3(
|
||||
|
@ -664,6 +691,10 @@ where T: Copy + Clone +
|
|||
impl<T: Copy, Src, Dst> TypedTransform3D<T, Src, Dst> {
|
||||
/// Returns an array containing this transform's terms in row-major order (the order
|
||||
/// in which the transform is actually laid out in memory).
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), then please use `to_column_major_array`
|
||||
pub fn to_row_major_array(&self) -> [T; 16] {
|
||||
[
|
||||
self.m11, self.m12, self.m13, self.m14,
|
||||
|
@ -674,6 +705,10 @@ impl<T: Copy, Src, Dst> TypedTransform3D<T, Src, Dst> {
|
|||
}
|
||||
|
||||
/// Returns an array containing this transform's terms in column-major order.
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), then please use `to_row_major_array`
|
||||
pub fn to_column_major_array(&self) -> [T; 16] {
|
||||
[
|
||||
self.m11, self.m21, self.m31, self.m41,
|
||||
|
@ -687,6 +722,10 @@ impl<T: Copy, Src, Dst> TypedTransform3D<T, Src, Dst> {
|
|||
/// as arrays.
|
||||
///
|
||||
/// This is a convenience method to interface with other libraries like glium.
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), then please use `to_column_arrays`
|
||||
pub fn to_row_arrays(&self) -> [[T; 4]; 4] {
|
||||
[
|
||||
[self.m11, self.m12, self.m13, self.m14],
|
||||
|
@ -700,6 +739,10 @@ impl<T: Copy, Src, Dst> TypedTransform3D<T, Src, Dst> {
|
|||
/// or 4 rows in column-major order) as arrays.
|
||||
///
|
||||
/// This is a convenience method to interface with other libraries like glium.
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), then please use `to_row_arrays`
|
||||
pub fn to_column_arrays(&self) -> [[T; 4]; 4] {
|
||||
[
|
||||
[self.m11, self.m21, self.m31, self.m41],
|
||||
|
@ -710,6 +753,10 @@ impl<T: Copy, Src, Dst> TypedTransform3D<T, Src, Dst> {
|
|||
}
|
||||
|
||||
/// Creates a transform from an array of 16 elements in row-major order.
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), please provide column-major data to this function.
|
||||
pub fn from_array(array: [T; 16]) -> Self {
|
||||
Self::row_major(
|
||||
array[0], array[1], array[2], array[3],
|
||||
|
@ -720,6 +767,10 @@ impl<T: Copy, Src, Dst> TypedTransform3D<T, Src, Dst> {
|
|||
}
|
||||
|
||||
/// Creates a transform from 4 rows of 4 elements (row-major order).
|
||||
///
|
||||
/// Beware: This library is written with the assumption that row vectors
|
||||
/// are being used. If your matrices use column vectors (i.e. transforming a vector
|
||||
/// is `T * v`), please provide column-major data to tis function.
|
||||
pub fn from_row_arrays(array: [[T; 4]; 4]) -> Self {
|
||||
Self::row_major(
|
||||
array[0][0], array[0][1], array[0][2], array[0][3],
|
||||
|
|
|
@ -63,6 +63,11 @@ where
|
|||
pub fn to_array(&self) -> [T; 2] {
|
||||
[self.x, self.y]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_tuple(&self) -> (T, T) {
|
||||
(self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Src, Dst> TypedTranslation2D<T, Src, Dst>
|
||||
|
@ -264,6 +269,11 @@ where
|
|||
pub fn to_array(&self) -> [T; 3] {
|
||||
[self.x, self.y, self.z]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_tuple(&self) -> (T, T, T) {
|
||||
(self.x, self.y, self.z)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Src, Dst> TypedTranslation3D<T, Src, Dst>
|
||||
|
|
|
@ -15,6 +15,8 @@ use mint;
|
|||
use point::{TypedPoint2D, TypedPoint3D, point2, point3};
|
||||
use size::{TypedSize2D, size2};
|
||||
use scale::TypedScale;
|
||||
use transform2d::TypedTransform2D;
|
||||
use transform3d::TypedTransform3D;
|
||||
use trig::Trig;
|
||||
use Angle;
|
||||
use num::*;
|
||||
|
@ -66,6 +68,12 @@ impl<T: fmt::Display, U> fmt::Display for TypedVector2D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Default, U> Default for TypedVector2D<T, U> {
|
||||
fn default() -> Self {
|
||||
TypedVector2D::new(Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedVector2D<T, U> {
|
||||
/// Constructor taking scalar values directly.
|
||||
#[inline]
|
||||
|
@ -135,10 +143,39 @@ impl<T: Copy, U> TypedVector2D<T, U> {
|
|||
vec2(p.x, p.y)
|
||||
}
|
||||
|
||||
/// Cast the unit
|
||||
#[inline]
|
||||
pub fn cast_unit<V>(&self) -> TypedVector2D<T, V> {
|
||||
vec2(self.x, self.y)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_array(&self) -> [T; 2] {
|
||||
[self.x, self.y]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_tuple(&self) -> (T, T) {
|
||||
(self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedVector2D<T, U>
|
||||
where
|
||||
T: Copy
|
||||
+ Clone
|
||||
+ Add<T, Output = T>
|
||||
+ Mul<T, Output = T>
|
||||
+ Div<T, Output = T>
|
||||
+ Sub<T, Output = T>
|
||||
+ Trig
|
||||
+ PartialOrd
|
||||
+ One
|
||||
+ Zero {
|
||||
#[inline]
|
||||
pub fn to_transform(&self) -> TypedTransform2D<T, U, U> {
|
||||
TypedTransform2D::create_translation(self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedVector2D<T, U>
|
||||
|
@ -462,6 +499,18 @@ impl<T: Copy, U> From<[T; 2]> for TypedVector2D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> Into<(T, T)> for TypedVector2D<T, U> {
|
||||
fn into(self) -> (T, T) {
|
||||
self.to_tuple()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> From<(T, T)> for TypedVector2D<T, U> {
|
||||
fn from(tuple: (T, T)) -> Self {
|
||||
vec2(tuple.0, tuple.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedVector2D<T, U>
|
||||
where
|
||||
T: Signed,
|
||||
|
@ -500,6 +549,11 @@ impl<T: Copy + Zero, U> TypedVector3D<T, U> {
|
|||
pub fn to_array_4d(&self) -> [T; 4] {
|
||||
[self.x, self.y, self.z, Zero::zero()]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_tuple_4d(&self) -> (T, T, T, T) {
|
||||
(self.x, self.y, self.z, Zero::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug, U> fmt::Debug for TypedVector3D<T, U> {
|
||||
|
@ -514,6 +568,12 @@ impl<T: fmt::Display, U> fmt::Display for TypedVector3D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Default, U> Default for TypedVector3D<T, U> {
|
||||
fn default() -> Self {
|
||||
TypedVector3D::new(Default::default(), Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedVector3D<T, U> {
|
||||
/// Constructor taking scalar values directly.
|
||||
#[inline]
|
||||
|
@ -583,6 +643,11 @@ impl<T: Copy, U> TypedVector3D<T, U> {
|
|||
[self.x, self.y, self.z]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_tuple(&self) -> (T, T, T) {
|
||||
(self.x, self.y, self.z)
|
||||
}
|
||||
|
||||
/// Drop the units, preserving only the numeric value.
|
||||
#[inline]
|
||||
pub fn to_untyped(&self) -> Vector3D<T> {
|
||||
|
@ -602,6 +667,25 @@ impl<T: Copy, U> TypedVector3D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedVector3D<T, U>
|
||||
where
|
||||
T: Copy
|
||||
+ Clone
|
||||
+ Add<T, Output = T>
|
||||
+ Mul<T, Output = T>
|
||||
+ Div<T, Output = T>
|
||||
+ Sub<T, Output = T>
|
||||
+ Trig
|
||||
+ PartialOrd
|
||||
+ One
|
||||
+ Zero
|
||||
+ Neg<Output = T> {
|
||||
#[inline]
|
||||
pub fn to_transform(&self) -> TypedTransform3D<T, U, U> {
|
||||
TypedTransform3D::create_translation(self.x, self.y, self.z)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Mul<T, Output = T> + Add<T, Output = T> + Sub<T, Output = T> + Copy, U>
|
||||
TypedVector3D<T, U> {
|
||||
// Dot product.
|
||||
|
@ -930,6 +1014,18 @@ impl<T: Copy, U> From<[T; 3]> for TypedVector3D<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> Into<(T, T, T)> for TypedVector3D<T, U> {
|
||||
fn into(self) -> (T, T, T) {
|
||||
self.to_tuple()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, U> From<(T, T, T)> for TypedVector3D<T, U> {
|
||||
fn from(tuple: (T, T, T)) -> Self {
|
||||
vec3(tuple.0, tuple.1, tuple.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TypedVector3D<T, U>
|
||||
where
|
||||
T: Signed,
|
||||
|
|
Загрузка…
Ссылка в новой задаче