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:
Dan Glastonbury 2019-07-12 06:12:31 +00:00
parent 73ed10d490
commit 866dcdad61
43 changed files with 4928 additions and 286 deletions

40
Cargo.lock generated
View File

@ -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"

64
gfx/wr/Cargo.lock generated
View File

@ -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"

View File

@ -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" }

View File

@ -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"]

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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"

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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);

View File

@ -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
}
}

427
gfx/wr/peek-poke/src/lib.rs Normal file
View File

@ -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);

View File

@ -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()) }
}
}

View File

@ -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);
}
}

View File

@ -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>())
}

View File

@ -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)));
}
}

View File

@ -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"

View File

@ -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)

View File

@ -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,

View File

@ -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
}

View File

@ -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();
(

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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>;

View File

@ -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"}

View File

@ -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/"

View File

@ -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);
}
}

793
third_party/rust/euclid/src/box2d.rs vendored Normal file
View File

@ -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());
}
}
}

842
third_party/rust/euclid/src/box3d.rs vendored Normal file
View File

@ -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());
}
}
}

View File

@ -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

View File

@ -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)
}

View File

@ -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));

261
third_party/rust/euclid/src/rigid.rs vendored Normal file
View File

@ -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())));
}
}

View File

@ -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]

View File

@ -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> {

View File

@ -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,
}
}
}

View File

@ -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> {

View File

@ -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],

View File

@ -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>

View File

@ -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,