diff --git a/.cargo/config.in b/.cargo/config.in index 5403491e24b4..9b00fc50272c 100644 --- a/.cargo/config.in +++ b/.cargo/config.in @@ -15,7 +15,7 @@ tag = "v0.4.10" [source."https://github.com/mozilla/mp4parse-rust"] git = "https://github.com/mozilla/mp4parse-rust" replace-with = "vendored-sources" -rev = "63325444ae3388599f2f222775eebdde4c2f9f30" +rev = "d5a37fd0bd51e06a53274c68213b00136aba83a6" [source."https://github.com/mozilla/application-services"] git = "https://github.com/mozilla/application-services" diff --git a/Cargo.lock b/Cargo.lock index d5855741e4f9..8a47aa03e550 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3121,7 +3121,7 @@ dependencies = [ [[package]] name = "mp4parse" version = "0.11.4" -source = "git+https://github.com/mozilla/mp4parse-rust?rev=63325444ae3388599f2f222775eebdde4c2f9f30#63325444ae3388599f2f222775eebdde4c2f9f30" +source = "git+https://github.com/mozilla/mp4parse-rust?rev=d5a37fd0bd51e06a53274c68213b00136aba83a6#d5a37fd0bd51e06a53274c68213b00136aba83a6" dependencies = [ "bitreader", "byteorder", @@ -3138,7 +3138,7 @@ version = "0.1.0" [[package]] name = "mp4parse_capi" version = "0.11.4" -source = "git+https://github.com/mozilla/mp4parse-rust?rev=63325444ae3388599f2f222775eebdde4c2f9f30#63325444ae3388599f2f222775eebdde4c2f9f30" +source = "git+https://github.com/mozilla/mp4parse-rust?rev=d5a37fd0bd51e06a53274c68213b00136aba83a6#d5a37fd0bd51e06a53274c68213b00136aba83a6" dependencies = [ "byteorder", "log", @@ -3388,19 +3388,21 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.39" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" +checksum = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" dependencies = [ + "autocfg 0.1.6", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.37" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" +checksum = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" dependencies = [ + "autocfg 0.1.6", "num-integer", "num-traits", ] diff --git a/third_party/rust/mp4parse/.cargo-checksum.json b/third_party/rust/mp4parse/.cargo-checksum.json index 6fc356ff099b..7826f0ffa9cd 100644 --- a/third_party/rust/mp4parse/.cargo-checksum.json +++ b/third_party/rust/mp4parse/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"107804fbf8f667fbad45e7dea9fa1bb32ce8ef5580b543a54455e678d7769708","src/boxes.rs":"5f84805435af90034075709867e02c74a198e26dc628a9fc95df034928ee5bbc","src/fallible.rs":"836a36c2bc9803aead4bb24621e4fa6176c77b3752e69459a1f36555eb8bf2ec","src/lib.rs":"7c8bde48b42f5470a937d3affc4452e06b2158ff07c207f39376bdca11efa832","src/macros.rs":"76c840f9299797527fe71aa5b378ffb01312767372b45cc62deddb19775400ae","src/tests.rs":"f1a27e785d4006cd910ca3c48c8a972da1db9c9b4a67185f67a191ddc3c69328","tests/bug-1655846.avif":"e0a5a06225800fadf05f5352503a4cec11af73eef705c43b4acab5f4a99dea50","tests/overflow.rs":"16b591d8def1a155b3b997622f6ea255536870d99c3d8f97c51755b77a50de3c","tests/public.rs":"fd646ffd5fab8beed5949b87482048ba400438fa90860f86f357a7f6141dc649"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"f48619a9cfbcfcaf657d6b1e4894d2c68afd4b1c620d42d6923f814611bf6186","src/boxes.rs":"5f84805435af90034075709867e02c74a198e26dc628a9fc95df034928ee5bbc","src/fallible.rs":"7dc89699f1e75433ab5c6bbd23807383b3b918fe572d41e68e5a270591b0a4ab","src/lib.rs":"ff16461743a5e09c2dc8ade092206e4c84ddcae061766b38d53eff6f94916b2e","src/macros.rs":"76c840f9299797527fe71aa5b378ffb01312767372b45cc62deddb19775400ae","src/tests.rs":"f1a27e785d4006cd910ca3c48c8a972da1db9c9b4a67185f67a191ddc3c69328","tests/bug-1655846.avif":"e0a5a06225800fadf05f5352503a4cec11af73eef705c43b4acab5f4a99dea50","tests/overflow.rs":"16b591d8def1a155b3b997622f6ea255536870d99c3d8f97c51755b77a50de3c","tests/public.rs":"fd646ffd5fab8beed5949b87482048ba400438fa90860f86f357a7f6141dc649"},"package":null} \ No newline at end of file diff --git a/third_party/rust/mp4parse/Cargo.toml b/third_party/rust/mp4parse/Cargo.toml index 83623eb4357b..1c99a78ded6a 100644 --- a/third_party/rust/mp4parse/Cargo.toml +++ b/third_party/rust/mp4parse/Cargo.toml @@ -28,7 +28,7 @@ travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" } byteorder = "1.2.1" bitreader = { version = "0.3.2" } hashbrown = "0.7.1" -num-traits = "0.2.0" +num-traits = "=0.2.10" log = "0.4" static_assertions = "1.1.0" diff --git a/third_party/rust/mp4parse/src/fallible.rs b/third_party/rust/mp4parse/src/fallible.rs index d0494448214b..1246a3d8df61 100644 --- a/third_party/rust/mp4parse/src/fallible.rs +++ b/third_party/rust/mp4parse/src/fallible.rs @@ -256,7 +256,7 @@ impl TryVec { Ok(()) } - fn reserve(&mut self, additional: usize) -> Result<()> { + pub fn reserve(&mut self, additional: usize) -> Result<()> { #[cfg(feature = "mp4parse_fallible")] { let available = self diff --git a/third_party/rust/mp4parse/src/lib.rs b/third_party/rust/mp4parse/src/lib.rs index 0df227b86a72..872bfdcd32ae 100644 --- a/third_party/rust/mp4parse/src/lib.rs +++ b/third_party/rust/mp4parse/src/lib.rs @@ -58,7 +58,7 @@ impl ToU64 for usize { /// A trait to indicate a type can be infallibly converted to `usize`. /// This should only be implemented for infallible conversions, so only unsigned types are valid. -trait ToUsize { +pub trait ToUsize { fn to_usize(self) -> usize; } @@ -975,16 +975,16 @@ pub struct TrackTimeScale(pub T, pub usize); /// A time to be scaled by the track's local (mdhd) timescale. /// Members are time in scale units and the track id. #[derive(Debug, Copy, Clone, PartialEq)] -pub struct TrackScaledTime(pub T, pub usize); +pub struct TrackScaledTime(pub T, pub usize); impl std::ops::Add for TrackScaledTime where - T: Num, + T: num_traits::CheckedAdd, { - type Output = TrackScaledTime; + type Output = Option; - fn add(self, other: TrackScaledTime) -> TrackScaledTime { - TrackScaledTime::(self.0 + other.0, self.1) + fn add(self, other: TrackScaledTime) -> Self::Output { + self.0.checked_add(&other.0).map(|sum| Self(sum, self.1)) } } @@ -1953,6 +1953,7 @@ fn read_stbl(f: &mut BMFFBox, track: &mut Track) -> Result<()> { } /// Parse an ftyp box. +/// See ISO 14496-12:2015 § 4.3 fn read_ftyp(src: &mut BMFFBox) -> Result { let major = be_u32(src)?; let minor = be_u32(src)?; @@ -1962,7 +1963,7 @@ fn read_ftyp(src: &mut BMFFBox) -> Result { } // Is a brand_count of zero valid? let brand_count = bytes_left / 4; - let mut brands = TryVec::new(); + let mut brands = TryVec::with_capacity(brand_count.try_into()?)?; for _ in 0..brand_count { brands.push(be_u32(src)?.into())?; } @@ -2058,10 +2059,11 @@ fn read_tkhd(src: &mut BMFFBox) -> Result { } /// Parse a elst box. +/// See ISO 14496-12:2015 § 8.6.6 fn read_elst(src: &mut BMFFBox) -> Result { let (version, _) = read_fullbox_extra(src)?; let edit_count = be_u32_with_limit(src)?; - let mut edits = TryVec::new(); + let mut edits = TryVec::with_capacity(edit_count.to_usize())?; for _ in 0..edit_count { let (segment_duration, media_time) = match version { 1 => { @@ -2133,10 +2135,11 @@ fn read_mdhd(src: &mut BMFFBox) -> Result { } /// Parse a stco box. +/// See ISO 14496-12:2015 § 8.7.5 fn read_stco(src: &mut BMFFBox) -> Result { let (_, _) = read_fullbox_extra(src)?; let offset_count = be_u32_with_limit(src)?; - let mut offsets = TryVec::new(); + let mut offsets = TryVec::with_capacity(offset_count.to_usize())?; for _ in 0..offset_count { offsets.push(be_u32(src)?.into())?; } @@ -2148,10 +2151,11 @@ fn read_stco(src: &mut BMFFBox) -> Result { } /// Parse a co64 box. +/// See ISO 14496-12:2015 § 8.7.5 fn read_co64(src: &mut BMFFBox) -> Result { let (_, _) = read_fullbox_extra(src)?; let offset_count = be_u32_with_limit(src)?; - let mut offsets = TryVec::new(); + let mut offsets = TryVec::with_capacity(offset_count.to_usize())?; for _ in 0..offset_count { offsets.push(be_u64(src)?)?; } @@ -2163,10 +2167,11 @@ fn read_co64(src: &mut BMFFBox) -> Result { } /// Parse a stss box. +/// See ISO 14496-12:2015 § 8.6.2 fn read_stss(src: &mut BMFFBox) -> Result { let (_, _) = read_fullbox_extra(src)?; let sample_count = be_u32_with_limit(src)?; - let mut samples = TryVec::new(); + let mut samples = TryVec::with_capacity(sample_count.to_usize())?; for _ in 0..sample_count { samples.push(be_u32(src)?)?; } @@ -2178,10 +2183,11 @@ fn read_stss(src: &mut BMFFBox) -> Result { } /// Parse a stsc box. +/// See ISO 14496-12:2015 § 8.7.4 fn read_stsc(src: &mut BMFFBox) -> Result { let (_, _) = read_fullbox_extra(src)?; let sample_count = be_u32_with_limit(src)?; - let mut samples = TryVec::new(); + let mut samples = TryVec::with_capacity(sample_count.to_usize())?; for _ in 0..sample_count { let first_chunk = be_u32(src)?; let samples_per_chunk = be_u32_with_limit(src)?; @@ -2199,16 +2205,23 @@ fn read_stsc(src: &mut BMFFBox) -> Result { Ok(SampleToChunkBox { samples }) } +/// Parse a Composition Time to Sample Box +/// See ISO 14496-12:2015 § 8.6.1.3 fn read_ctts(src: &mut BMFFBox) -> Result { let (version, _) = read_fullbox_extra(src)?; - let counts = u64::from(be_u32_with_limit(src)?); + let counts = be_u32_with_limit(src)?; - if src.bytes_left() < counts.checked_mul(8).expect("counts -> bytes overflow") { + if src.bytes_left() + < counts + .checked_mul(8) + .expect("counts -> bytes overflow") + .into() + { return Err(Error::InvalidData("insufficient data in 'ctts' box")); } - let mut offsets = TryVec::new(); + let mut offsets = TryVec::with_capacity(counts.to_usize())?; for _ in 0..counts { let (sample_count, time_offset) = match version { // According to spec, Version0 shoule be used when version == 0; @@ -2235,12 +2248,14 @@ fn read_ctts(src: &mut BMFFBox) -> Result { } /// Parse a stsz box. +/// See ISO 14496-12:2015 § 8.7.3.2 fn read_stsz(src: &mut BMFFBox) -> Result { let (_, _) = read_fullbox_extra(src)?; let sample_size = be_u32(src)?; let sample_count = be_u32_with_limit(src)?; let mut sample_sizes = TryVec::new(); if sample_size == 0 { + sample_sizes.reserve(sample_count.to_usize())?; for _ in 0..sample_count { sample_sizes.push(be_u32(src)?)?; } @@ -2256,10 +2271,11 @@ fn read_stsz(src: &mut BMFFBox) -> Result { } /// Parse a stts box. +/// See ISO 14496-12:2015 § 8.6.1.2 fn read_stts(src: &mut BMFFBox) -> Result { let (_, _) = read_fullbox_extra(src)?; let sample_count = be_u32_with_limit(src)?; - let mut samples = TryVec::new(); + let mut samples = TryVec::with_capacity(sample_count.to_usize())?; for _ in 0..sample_count { let sample_count = be_u32_with_limit(src)?; let sample_delta = be_u32(src)?; @@ -2421,7 +2437,7 @@ fn find_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> { let des = &mut Cursor::new(remains); let tag = des.read_u8()?; - // See ISO 14496-1:2010 § 8.3.3 for interpreting size of exandable classes + // See ISO 14496-1:2010 § 8.3.3 for interpreting size of expandable classes let mut end: u32 = 0; // It's u8 without declaration type that is incorrect. // MSB of extend_or_len indicates more bytes, up to 4 bytes. @@ -2627,7 +2643,11 @@ fn read_ds_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> { esds.extended_audio_object_type = extended_audio_object_type; esds.audio_sample_rate = Some(sample_frequency_value); esds.audio_channel_count = Some(channel_counts); - assert!(esds.decoder_specific_data.is_empty()); + if !esds.decoder_specific_data.is_empty() { + return Err(Error::InvalidData( + "There can be only one DecSpecificInfoTag descriptor", + )); + } esds.decoder_specific_data.extend_from_slice(data)?; Ok(()) @@ -2695,6 +2715,7 @@ fn read_es_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> { Ok(()) } +/// See ISO 14496-14:2010 § 6.7.2 fn read_esds(src: &mut BMFFBox) -> Result { let (_, _) = read_fullbox_extra(src)?; @@ -2709,6 +2730,7 @@ fn read_esds(src: &mut BMFFBox) -> Result { } /// Parse `FLACSpecificBox`. +/// See https://github.com/xiph/flac/blob/master/doc/isoflac.txt § 3.3.2 fn read_dfla(src: &mut BMFFBox) -> Result { let (version, flags) = read_fullbox_extra(src)?; if version != 0 { @@ -3135,6 +3157,7 @@ fn read_audio_sample_entry(src: &mut BMFFBox) -> Result /// Parse a stsd box. /// See ISO 14496-12:2015 § 8.5.2 +/// See ISO 14496-14:2010 § 6.7.2 fn read_stsd(src: &mut BMFFBox, track: &mut Track) -> Result { let (_, _) = read_fullbox_extra(src)?; diff --git a/third_party/rust/mp4parse_capi/.cargo-checksum.json b/third_party/rust/mp4parse_capi/.cargo-checksum.json index 00fb14d110e8..ef646676f0ac 100644 --- a/third_party/rust/mp4parse_capi/.cargo-checksum.json +++ b/third_party/rust/mp4parse_capi/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"13408d7785c5fe40f9db2bac1f93e8cf2aca7c35b5d2ba9acbbb23eb3a71e40a","cbindgen.toml":"5c9429f271d6e914d81b63e6509c04ffe84cab11ed3a53a2ed4715e5d5ace80e","examples/dump.rs":"598f828f07bac9b204d3eb7af4efd7158087382fc322dcce913a28729f854f70","src/lib.rs":"dfd3bccfb80aaab2389d11ae00242709d6c5dae8a299b55098bf5ec39698a097","tests/test_chunk_out_of_range.rs":"b5da583218d98027ed973a29c67434a91a1306f2d2fb39ec4d640d4824c308ce","tests/test_encryption.rs":"ca98516ff423c03b5fcc17b05f993f13b32485e4cf3ba86faf1bea72681d75ce","tests/test_fragment.rs":"e90eb5a4418d30002655466c0c4b3125c7fd70a74b6871471eaa172f1def9db8","tests/test_rotation.rs":"fb43c2f2dfa496d151c33bdd46c0fd3252387c23cc71e2cac9ed0234de715a81","tests/test_sample_table.rs":"adc8d264c46aef78c047377fbb792a4400d6db98bc44583b464d7b3dc182c884","tests/test_workaround_stsc.rs":"7dd419f3d55b9a3a039cac57e58a9240a9c8166bcd4356c24f69f731c3ced83b"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"12f3f7561fa1d5facc70b63b68288997ca6fde3dd5d6fabcfe2e7d8ec5940ab2","cbindgen.toml":"5c9429f271d6e914d81b63e6509c04ffe84cab11ed3a53a2ed4715e5d5ace80e","examples/dump.rs":"83462422315c22e496960bae922edb23105c0aa272d2b106edd7574ff068513a","src/lib.rs":"e90c6bdfcf321115b19f0148b5f273c9516bc7dfdae16c7c01a76ba8be51dad3","tests/test_chunk_out_of_range.rs":"b5da583218d98027ed973a29c67434a91a1306f2d2fb39ec4d640d4824c308ce","tests/test_encryption.rs":"ca98516ff423c03b5fcc17b05f993f13b32485e4cf3ba86faf1bea72681d75ce","tests/test_fragment.rs":"e90eb5a4418d30002655466c0c4b3125c7fd70a74b6871471eaa172f1def9db8","tests/test_rotation.rs":"fb43c2f2dfa496d151c33bdd46c0fd3252387c23cc71e2cac9ed0234de715a81","tests/test_sample_table.rs":"185755909b2f4e0ea99604bb423a07623d614a180accdaebd1c98aef2c2e3ae6","tests/test_workaround_stsc.rs":"7dd419f3d55b9a3a039cac57e58a9240a9c8166bcd4356c24f69f731c3ced83b"},"package":null} \ No newline at end of file diff --git a/third_party/rust/mp4parse_capi/Cargo.toml b/third_party/rust/mp4parse_capi/Cargo.toml index 2904775e7214..13cd2440b3bf 100644 --- a/third_party/rust/mp4parse_capi/Cargo.toml +++ b/third_party/rust/mp4parse_capi/Cargo.toml @@ -26,7 +26,7 @@ travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" } byteorder = "1.2.1" log = "0.4" mp4parse = {version = "0.11.2", path = "../mp4parse"} -num-traits = "0.2.0" +num-traits = "=0.2.10" [dev-dependencies] env_logger = "0.7.1" diff --git a/third_party/rust/mp4parse_capi/examples/dump.rs b/third_party/rust/mp4parse_capi/examples/dump.rs index 5907f5d701b6..d00fdf5e9334 100644 --- a/third_party/rust/mp4parse_capi/examples/dump.rs +++ b/third_party/rust/mp4parse_capi/examples/dump.rs @@ -62,9 +62,7 @@ fn dump_file(filename: &str) { for i in 0..counts { let mut track_info = Mp4parseTrackInfo { track_type: Mp4parseTrackType::Audio, - track_id: 0, - duration: 0, - media_time: 0, + ..Default::default() }; match mp4parse_get_track_info(parser, i, &mut track_info) { Mp4parseStatus::Ok => { diff --git a/third_party/rust/mp4parse_capi/src/lib.rs b/third_party/rust/mp4parse_capi/src/lib.rs index ff26d2dfb49f..e85e4cccb6e6 100644 --- a/third_party/rust/mp4parse_capi/src/lib.rs +++ b/third_party/rust/mp4parse_capi/src/lib.rs @@ -40,8 +40,14 @@ extern crate mp4parse; extern crate num_traits; use byteorder::WriteBytesExt; +use num_traits::{CheckedAdd, CheckedSub}; use num_traits::{PrimInt, Zero}; +use std::convert::TryFrom; +use std::convert::TryInto; + use std::io::Read; +use std::ops::Neg; +use std::ops::{Add, Sub}; // Symbols we need from our rust api. use mp4parse::read_avif; @@ -55,6 +61,7 @@ use mp4parse::MediaContext; use mp4parse::MediaScaledTime; use mp4parse::MediaTimeScale; use mp4parse::SampleEntry; +use mp4parse::ToUsize; use mp4parse::Track; use mp4parse::TrackScaledTime; use mp4parse::TrackTimeScale; @@ -144,36 +151,134 @@ impl Default for Mp4ParseEncryptionSchemeType { } } +/// A zero-overhead wrapper around integer types for the sake of always +/// requiring checked arithmetic +#[repr(transparent)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct CheckedInteger(pub T); + +impl From for CheckedInteger { + fn from(i: T) -> Self { + Self(i) + } +} + +// Orphan rules prevent a more general implementation, but this suffices +impl From> for i64 { + fn from(checked: CheckedInteger) -> i64 { + checked.0 + } +} + +impl> Add for CheckedInteger +where + T: CheckedAdd, +{ + type Output = Option; + + fn add(self, other: U) -> Self::Output { + self.0.checked_add(&other.into()).map(Into::into) + } +} + +impl> Sub for CheckedInteger +where + T: CheckedSub, +{ + type Output = Option; + + fn sub(self, other: U) -> Self::Output { + self.0.checked_sub(&other.into()).map(Into::into) + } +} + +/// Implement subtraction of checked `u64`s returning i64 +// This is necessary for handling Mp4parseTrackInfo::media_time gracefully +impl Sub for CheckedInteger { + type Output = Option>; + + fn sub(self, other: Self) -> Self::Output { + if self >= other { + self.0 + .checked_sub(other.0) + .and_then(|u| i64::try_from(u).ok()) + .map(CheckedInteger) + } else { + other + .0 + .checked_sub(self.0) + .and_then(|u| i64::try_from(u).ok()) + .map(i64::neg) + .map(CheckedInteger) + } + } +} + +#[test] +fn u64_subtraction_returning_i64() { + // self > other + assert_eq!( + CheckedInteger(2u64) - CheckedInteger(1u64), + Some(CheckedInteger(1i64)) + ); + + // self == other + assert_eq!( + CheckedInteger(1u64) - CheckedInteger(1u64), + Some(CheckedInteger(0i64)) + ); + + // difference too large to store in i64 + assert_eq!(CheckedInteger(u64::MAX) - CheckedInteger(1u64), None); + + // self < other + assert_eq!( + CheckedInteger(1u64) - CheckedInteger(2u64), + Some(CheckedInteger(-1i64)) + ); + + // difference not representable due to overflow + assert_eq!(CheckedInteger(1u64) - CheckedInteger(u64::MAX), None); +} + +impl PartialEq for CheckedInteger { + fn eq(&self, other: &T) -> bool { + self.0 == *other + } +} + #[repr(C)] #[derive(Default, Debug)] pub struct Mp4parseTrackInfo { pub track_type: Mp4parseTrackType, pub track_id: u32, pub duration: u64, - pub media_time: i64, // wants to be u64? understand how elst adjustment works - // TODO(kinetik): include crypto guff + pub media_time: CheckedInteger, // wants to be u64? understand how elst adjustment works + // TODO(kinetik): include crypto guff + // If this changes to u64, we can get rid of the strange + // impl Sub for CheckedInteger } #[repr(C)] #[derive(Default, Debug, PartialEq)] pub struct Mp4parseIndice { /// The byte offset in the file where the indexed sample begins. - pub start_offset: u64, + pub start_offset: CheckedInteger, /// The byte offset in the file where the indexed sample ends. This is /// equivalent to `start_offset` + the length in bytes of the indexed /// sample. Typically this will be the `start_offset` of the next sample /// in the file. - pub end_offset: u64, + pub end_offset: CheckedInteger, /// The time in microseconds when the indexed sample should be displayed. /// Analogous to the concept of presentation time stamp (pts). - pub start_composition: i64, + pub start_composition: CheckedInteger, /// The time in microseconds when the indexed sample should stop being /// displayed. Typically this would be the `start_composition` time of the /// next sample if samples were ordered by composition time. - pub end_composition: i64, + pub end_composition: CheckedInteger, /// The time in microseconds that the indexed sample should be decoded at. /// Analogous to the concept of decode time stamp (dts). - pub start_decode: i64, + pub start_decode: CheckedInteger, /// Set if the indexed sample is a sync sample. The meaning of sync is /// somewhat codec specific, but essentially amounts to if the sample is a /// key frame. @@ -660,19 +765,23 @@ pub unsafe extern "C" fn mp4parse_get_track_info( let track = &context.tracks[track_index]; if let (Some(track_timescale), Some(context_timescale)) = (track.timescale, context.timescale) { - let media_time = match track.media_time.map_or(Some(0), |media_time| { + let media_time: CheckedInteger<_> = match track.media_time.map_or(Some(0), |media_time| { track_time_to_us(media_time, track_timescale) }) { - Some(time) => time as i64, + Some(time) => time.into(), None => return Mp4parseStatus::Invalid, }; - let empty_duration = match track.empty_duration.map_or(Some(0), |empty_duration| { - media_time_to_us(empty_duration, context_timescale) - }) { - Some(time) => time as i64, + let empty_duration: CheckedInteger<_> = + match track.empty_duration.map_or(Some(0), |empty_duration| { + media_time_to_us(empty_duration, context_timescale) + }) { + Some(time) => time.into(), + None => return Mp4parseStatus::Invalid, + }; + info.media_time = match media_time - empty_duration { + Some(difference) => difference, None => return Mp4parseStatus::Invalid, }; - info.media_time = media_time - empty_duration; if let Some(track_duration) = track.duration { match track_time_to_us(track_duration, track_timescale) { @@ -1135,23 +1244,28 @@ fn get_indice_table( } let media_time = match (&track.media_time, &track.timescale) { - (&Some(t), &Some(s)) => track_time_to_us(t, s).map(|v| v as i64), + (&Some(t), &Some(s)) => track_time_to_us(t, s) + .and_then(|v| i64::try_from(v).ok()) + .map(Into::into), _ => None, }; - let empty_duration = match (&track.empty_duration, &context.timescale) { - (&Some(e), &Some(s)) => media_time_to_us(e, s).map(|v| v as i64), - _ => None, - }; + let empty_duration: Option> = + match (&track.empty_duration, &context.timescale) { + (&Some(e), &Some(s)) => media_time_to_us(e, s) + .and_then(|v| i64::try_from(v).ok()) + .map(Into::into), + _ => None, + }; // Find the track start offset time from 'elst'. // 'media_time' maps start time onward, 'empty_duration' adds time offset // before first frame is displayed. let offset_time = match (empty_duration, media_time) { - (Some(e), Some(m)) => e - m, + (Some(e), Some(m)) => (e - m).ok_or(Err(Mp4parseStatus::Invalid))?, (Some(e), None) => e, (None, Some(m)) => m, - _ => 0, + _ => 0.into(), }; if let Some(v) = create_sample_table(track, offset_time) { @@ -1178,6 +1292,7 @@ struct TimeOffsetIterator<'a> { impl<'a> Iterator for TimeOffsetIterator<'a> { type Item = i64; + #[allow(clippy::reversed_empty_ranges)] fn next(&mut self) -> Option { let has_sample = self.cur_sample_range.next().or_else(|| { // At end of current TimeOffset, find the next TimeOffset. @@ -1234,6 +1349,7 @@ struct TimeToSampleIterator<'a> { impl<'a> Iterator for TimeToSampleIterator<'a> { type Item = u32; + #[allow(clippy::reversed_empty_ranges)] fn next(&mut self) -> Option { let has_sample = self.cur_sample_count.next().or_else(|| { self.cur_sample_count = match self.stts_iter.next() { @@ -1271,6 +1387,21 @@ impl<'a> TimeToSampleIterator<'a> { // For example: // (1, 5), (5, 10), (9, 2) => (1, 5), (2, 5), (3, 5), (4, 5), (5, 10), (6, 10), // (7, 10), (8, 10), (9, 2) +fn sample_to_chunk_iter<'a>( + stsc_samples: &'a TryVec, + stco_offsets: &'a TryVec, +) -> SampleToChunkIterator<'a> { + SampleToChunkIterator { + chunks: (0..0), + sample_count: 0, + stsc_peek_iter: stsc_samples.as_slice().iter().peekable(), + remain_chunk_count: stco_offsets + .len() + .try_into() + .expect("stco.entry_count is u32"), + } +} + struct SampleToChunkIterator<'a> { chunks: std::ops::Range, sample_count: u32, @@ -1285,7 +1416,12 @@ impl<'a> Iterator for SampleToChunkIterator<'a> { let has_chunk = self.chunks.next().or_else(|| { self.chunks = self.locate(); self.remain_chunk_count - .checked_sub(self.chunks.len() as u32) + .checked_sub( + self.chunks + .len() + .try_into() + .expect("len() of a Range must fit in u32"), + ) .and_then(|res| { self.remain_chunk_count = res; self.chunks.next() @@ -1297,6 +1433,7 @@ impl<'a> Iterator for SampleToChunkIterator<'a> { } impl<'a> SampleToChunkIterator<'a> { + #[allow(clippy::reversed_empty_ranges)] fn locate(&mut self) -> std::ops::Range { loop { return match (self.stsc_peek_iter.next(), self.stsc_peek_iter.peek()) { @@ -1324,7 +1461,11 @@ impl<'a> SampleToChunkIterator<'a> { } } -fn create_sample_table(track: &Track, track_offset_time: i64) -> Option> { +#[allow(clippy::reversed_empty_ranges)] +fn create_sample_table( + track: &Track, + track_offset_time: CheckedInteger, +) -> Option> { let timescale = match track.timescale { Some(ref t) => TrackTimeScale::(t.0 as i64, t.1), _ => return None, @@ -1341,31 +1482,32 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option false, }; - let mut sample_table = TryVec::new(); let mut sample_size_iter = stsz.sample_sizes.iter(); // Get 'stsc' iterator for (chunk_id, chunk_sample_count) and calculate the sample // offset address. - let stsc_iter = SampleToChunkIterator { - chunks: (0..0), - sample_count: 0, - stsc_peek_iter: stsc.samples.as_slice().iter().peekable(), - remain_chunk_count: stco.offsets.len() as u32, - }; - for i in stsc_iter { + // With large numbers of samples, the cost of many allocations dominates, + // so it's worth iterating twice to allocate sample_table just once. + let total_sample_count = sample_to_chunk_iter(&stsc.samples, &stco.offsets) + .by_ref() + .map(|(_, sample_counts)| sample_counts.to_usize()) + .sum(); + let mut sample_table = TryVec::with_capacity(total_sample_count).ok()?; + + for i in sample_to_chunk_iter(&stsc.samples, &stco.offsets) { let chunk_id = i.0 as usize; let sample_counts = i.1; let mut cur_position = match stco.offsets.get(chunk_id) { - Some(&i) => i, + Some(&i) => i.into(), _ => return None, }; for _ in 0..sample_counts { let start_offset = cur_position; let end_offset = match (stsz.sample_size, sample_size_iter.next()) { - (_, Some(t)) => start_offset + u64::from(*t), - (t, _) if t > 0 => start_offset + u64::from(t), - _ => 0, + (_, Some(t)) => (start_offset + *t)?, + (t, _) if t > 0 => (start_offset + t)?, + _ => 0.into(), }; if end_offset == 0 { return None; @@ -1376,10 +1518,8 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option Option elem.sync = true, @@ -1426,25 +1566,20 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option(0, track.id); for sample in sample_table.as_mut_slice() { let decode_time = sum_delta; - sum_delta = sum_delta + stts_iter.next_delta(); + sum_delta = (sum_delta + stts_iter.next_delta())?; // ctts_offset is the current sample offset time. let ctts_offset = ctts_offset_iter.next_offset_time(); - let start_composition = track_time_to_us(decode_time + ctts_offset, timescale); + let start_composition = track_time_to_us((decode_time + ctts_offset)?, timescale)?; - let end_composition = track_time_to_us(sum_delta + ctts_offset, timescale); + let end_composition = track_time_to_us((sum_delta + ctts_offset)?, timescale)?; - let start_decode = track_time_to_us(decode_time, timescale); + let start_decode = track_time_to_us(decode_time, timescale)?; - match (start_composition, end_composition, start_decode) { - (Some(s_c), Some(e_c), Some(s_d)) => { - sample.start_composition = s_c + track_offset_time; - sample.end_composition = e_c + track_offset_time; - sample.start_decode = s_d; - } - _ => return None, - } + sample.start_composition = (track_offset_time + start_composition)?; + sample.end_composition = (track_offset_time + end_composition)?; + sample.start_decode = start_decode.into(); } // Correct composition end time due to 'ctts' causes composition time re-ordering. @@ -1453,14 +1588,15 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option v.start_composition, - _ => 0, + _ => 0.into(), }); for indices in sort_table.windows(2) { @@ -1600,13 +1736,14 @@ fn get_pssh_info( pssh_data.clear(); for pssh in &context.psshs { - let content_len = pssh.box_content.len(); - if content_len > std::u32::MAX as usize { - return Err(Mp4parseStatus::Invalid); - } + let content_len = pssh + .box_content + .len() + .try_into() + .map_err(|_| Mp4parseStatus::Invalid)?; let mut data_len = TryVec::new(); if data_len - .write_u32::(content_len as u32) + .write_u32::(content_len) .is_err() { return Err(Mp4parseStatus::Io); @@ -1684,9 +1821,7 @@ fn arg_validation() { let mut dummy_info = Mp4parseTrackInfo { track_type: Mp4parseTrackType::Video, - track_id: 0, - duration: 0, - media_time: 0, + ..Default::default() }; assert_eq!( Mp4parseStatus::BadArg, @@ -1754,9 +1889,7 @@ fn arg_validation_with_parser() { let mut dummy_info = Mp4parseTrackInfo { track_type: Mp4parseTrackType::Video, - track_id: 0, - duration: 0, - media_time: 0, + ..Default::default() }; assert_eq!( Mp4parseStatus::BadArg, @@ -1828,9 +1961,7 @@ fn minimal_mp4_get_track_info() { let mut info = Mp4parseTrackInfo { track_type: Mp4parseTrackType::Video, - track_id: 0, - duration: 0, - media_time: 0, + ..Default::default() }; assert_eq!(Mp4parseStatus::Ok, unsafe { mp4parse_get_track_info(parser, 0, &mut info) @@ -1902,9 +2033,7 @@ fn minimal_mp4_get_track_info_invalid_track_number() { let mut info = Mp4parseTrackInfo { track_type: Mp4parseTrackType::Video, - track_id: 0, - duration: 0, - media_time: 0, + ..Default::default() }; assert_eq!(Mp4parseStatus::BadArg, unsafe { mp4parse_get_track_info(parser, 3, &mut info) diff --git a/third_party/rust/mp4parse_capi/tests/test_sample_table.rs b/third_party/rust/mp4parse_capi/tests/test_sample_table.rs index d86ce8eda64c..018bfc8e9bc4 100644 --- a/third_party/rust/mp4parse_capi/tests/test_sample_table.rs +++ b/third_party/rust/mp4parse_capi/tests/test_sample_table.rs @@ -48,19 +48,19 @@ fn parse_sample_table() { // Compare the value from stagefright. let audio_indice_0 = Mp4parseIndice { - start_offset: 27_046, - end_offset: 27_052, - start_composition: 0, - end_composition: 46_439, - start_decode: 0, + start_offset: 27_046.into(), + end_offset: 27_052.into(), + start_composition: 0.into(), + end_composition: 46_439.into(), + start_decode: 0.into(), sync: true, }; let audio_indice_215 = Mp4parseIndice { - start_offset: 283_550, - end_offset: 283_556, - start_composition: 9_984_580, - end_composition: 10_031_020, - start_decode: 9_984_580, + start_offset: 283_550.into(), + end_offset: 283_556.into(), + start_composition: 9_984_580.into(), + end_composition: 10_031_020.into(), + start_decode: 9_984_580.into(), sync: true, }; assert_eq!(indice.length, 216); @@ -83,19 +83,19 @@ fn parse_sample_table() { // Compare the last few data from stagefright. let video_indice_291 = Mp4parseIndice { - start_offset: 280_226, - end_offset: 280_855, - start_composition: 9_838_333, - end_composition: 9_871_677, - start_decode: 9_710_000, + start_offset: 280_226.into(), + end_offset: 280_855.into(), + start_composition: 9_838_333.into(), + end_composition: 9_871_677.into(), + start_decode: 9_710_000.into(), sync: false, }; let video_indice_292 = Mp4parseIndice { - start_offset: 280_855, - end_offset: 281_297, - start_composition: 9_805_011, - end_composition: 9_838_333, - start_decode: 9_710_011, + start_offset: 280_855.into(), + end_offset: 281_297.into(), + start_composition: 9_805_011.into(), + end_composition: 9_838_333.into(), + start_decode: 9_710_011.into(), sync: false, }; // TODO: start_composition time in stagefright is 9905000, but it is 9904999 in parser, it @@ -103,19 +103,19 @@ fn parse_sample_table() { //let video_indice_293 = Mp4parseIndice { start_offset: 281_297, end_offset: 281_919, start_composition: 9_905_000, end_composition: 9_938_344, start_decode: 9_776_666, sync: false }; //let video_indice_294 = Mp4parseIndice { start_offset: 281_919, end_offset: 282_391, start_composition: 9_871_677, end_composition: 9_905_000, start_decode: 9_776_677, sync: false }; let video_indice_295 = Mp4parseIndice { - start_offset: 282_391, - end_offset: 283_032, - start_composition: 9_971_666, - end_composition: 9_971_677, - start_decode: 9_843_333, + start_offset: 282_391.into(), + end_offset: 283_032.into(), + start_composition: 9_971_666.into(), + end_composition: 9_971_677.into(), + start_decode: 9_843_333.into(), sync: false, }; let video_indice_296 = Mp4parseIndice { - start_offset: 283_092, - end_offset: 283_526, - start_composition: 9_938_344, - end_composition: 9_971_666, - start_decode: 9_843_344, + start_offset: 283_092.into(), + end_offset: 283_526.into(), + start_composition: 9_938_344.into(), + end_composition: 9_971_666.into(), + start_decode: 9_843_344.into(), sync: false, }; @@ -169,27 +169,27 @@ fn parse_sample_table_with_elst() { // Due to 'elst', the start_composition and end_composition are negative // at first two samples. let audio_indice_0 = Mp4parseIndice { - start_offset: 6992, - end_offset: 7363, - start_composition: -36281, - end_composition: -13062, - start_decode: 0, + start_offset: 6992.into(), + end_offset: 7363.into(), + start_composition: (-36281).into(), + end_composition: (-13062).into(), + start_decode: 0.into(), sync: true, }; let audio_indice_1 = Mp4parseIndice { - start_offset: 7363, - end_offset: 7735, - start_composition: -13062, - end_composition: 10158, - start_decode: 23219, + start_offset: 7363.into(), + end_offset: 7735.into(), + start_composition: (-13062).into(), + end_composition: 10158.into(), + start_decode: 23219.into(), sync: true, }; let audio_indice_2 = Mp4parseIndice { - start_offset: 7735, - end_offset: 8106, - start_composition: 10158, - end_composition: 33378, - start_decode: 46439, + start_offset: 7735.into(), + end_offset: 8106.into(), + start_composition: 10158.into(), + end_composition: 33378.into(), + start_decode: 46439.into(), sync: true, }; assert_eq!(indice.length, 21); @@ -236,35 +236,35 @@ fn parse_sample_table_with_negative_ctts() { // There are negative value in 'ctts' table. let video_indice_0 = Mp4parseIndice { - start_offset: 48, - end_offset: 890, - start_composition: 0, - end_composition: 33_333, - start_decode: 0, + start_offset: 48.into(), + end_offset: 890.into(), + start_composition: 0.into(), + end_composition: 33_333.into(), + start_decode: 0.into(), sync: true, }; let video_indice_1 = Mp4parseIndice { - start_offset: 890, - end_offset: 913, - start_composition: 133_333, - end_composition: 166_666, - start_decode: 33_333, + start_offset: 890.into(), + end_offset: 913.into(), + start_composition: 133_333.into(), + end_composition: 166_666.into(), + start_decode: 33_333.into(), sync: false, }; let video_indice_2 = Mp4parseIndice { - start_offset: 913, - end_offset: 934, - start_composition: 66_666, - end_composition: 100_000, - start_decode: 66_666, + start_offset: 913.into(), + end_offset: 934.into(), + start_composition: 66_666.into(), + end_composition: 100_000.into(), + start_decode: 66_666.into(), sync: false, }; let video_indice_3 = Mp4parseIndice { - start_offset: 934, - end_offset: 955, - start_composition: 33_333, - end_composition: 66_666, - start_decode: 100_000, + start_offset: 934.into(), + end_offset: 955.into(), + start_composition: 33_333.into(), + end_composition: 66_666.into(), + start_decode: 100_000.into(), sync: false, }; assert_eq!(indice.length, 300); diff --git a/third_party/rust/num-integer/.cargo-checksum.json b/third_party/rust/num-integer/.cargo-checksum.json index e8222de49dcd..1b932b50ba54 100644 --- a/third_party/rust/num-integer/.cargo-checksum.json +++ b/third_party/rust/num-integer/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"f491aec76f2252ca15a333dd3cfd18cfd91ebf841c7d607857dfa75c7080cb9a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"7ad5fb625f7ef61595a2180f3b26715457552faa8bb08526c70b416da29b2533","RELEASES.md":"ebe114c148e4fc43b63c2523e13e9d903f07db139ab70f48320f9cb8c17ac9d8","benches/roots.rs":"df3554c0025d78235b5dca975b641f3bb10cae8d5ad3a79eb6cbd1a21475f133","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","build.rs":"16de2aa57e754fc1526d0400b5d87a3f771296705fca54601aa598b6f74ded8f","ci/rustup.sh":"2aa9e89e4af81ed9da86bdcf7cdabe512287c877248783b69eed1eccf09ad6bb","ci/test_full.sh":"fd4928a73c13905d939d009801bd448a7a9d2ca00a30260eedd1feb03fc88e11","src/lib.rs":"1e19a19aa0d414d7548e4bc9510f89bed122430564e044302edd4a21a1b83134","src/roots.rs":"51a994a5e0bf505911cf912954283f52e7aa582ce0cd1c483e6b2e4c09a47b9e","tests/roots.rs":"ef70f711cb1544311c343dbaf411ad2598432e82b6dfa3d166c1d99096991d9e"},"package":"e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"} \ No newline at end of file +{"files":{"Cargo.toml":"54f4df5d505f0f8581a9455d2ea52bc385f003f97116c3d13b0e8e0cc491903f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"7ad5fb625f7ef61595a2180f3b26715457552faa8bb08526c70b416da29b2533","RELEASES.md":"ea8b30468b1d1c16ebe9e148a62df378cb9d3198bb4095c889fe521245690f9d","benches/gcd.rs":"9b5c0ae8ccd6c7fc8f8384fb351d10cfdd0be5fbea9365f9ea925d8915b015bf","benches/roots.rs":"79b4ab2d8fe7bbf43fe65314d2e1bc206165bc4cb34b3ceaa899f9ea7af31c09","build.rs":"56d4fbb7a55750e61d2074df2735a31995c1decbd988c0e722926235e0fed487","src/lib.rs":"937d6a77d6542b47aafb872df7181dcafc1ab596df0e5d78b2e6577ae9463dd0","src/roots.rs":"2a9b908bd3666b5cffc58c1b37d329e46ed02f71ad6d5deea1e8440c10660e1a","tests/roots.rs":"a0caa4142899ec8cb806a7a0d3410c39d50de97cceadc4c2ceca707be91b1ddd"},"package":"b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"} \ No newline at end of file diff --git a/third_party/rust/num-integer/Cargo.toml b/third_party/rust/num-integer/Cargo.toml index 14400ad4951b..3937fa1477ac 100644 --- a/third_party/rust/num-integer/Cargo.toml +++ b/third_party/rust/num-integer/Cargo.toml @@ -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,9 +12,10 @@ [package] name = "num-integer" -version = "0.1.39" +version = "0.1.41" authors = ["The Rust Project Developers"] build = "build.rs" +exclude = ["/ci/*", "/.travis.yml", "/bors.toml"] description = "Integer traits and functions" homepage = "https://github.com/rust-num/num-integer" documentation = "https://docs.rs/num-integer" @@ -28,6 +29,8 @@ features = ["std"] [dependencies.num-traits] version = "0.2.4" default-features = false +[build-dependencies.autocfg] +version = "0.1.3" [features] default = ["std"] diff --git a/third_party/rust/num-integer/RELEASES.md b/third_party/rust/num-integer/RELEASES.md index b20dbcbf1b58..ebc19f76cd51 100644 --- a/third_party/rust/num-integer/RELEASES.md +++ b/third_party/rust/num-integer/RELEASES.md @@ -1,4 +1,26 @@ -# Release 0.1.39 +# Release 0.1.41 (2019-05-21) + +- [Fixed feature detection on `no_std` targets][25]. + +**Contributors**: @cuviper + +[25]: https://github.com/rust-num/num-integer/pull/25 + +# Release 0.1.40 (2019-05-20) + +- [Optimized primitive `gcd` by avoiding memory swaps][11]. +- [Fixed `lcm(0, 0)` to return `0`, rather than panicking][18]. +- [Added `Integer::div_ceil`, `next_multiple_of`, and `prev_multiple_of`][16]. +- [Added `Integer::gcd_lcm`, `extended_gcd`, and `extended_gcd_lcm`][19]. + +**Contributors**: @cuviper, @ignatenkobrain, @smarnach, @strake + +[11]: https://github.com/rust-num/num-integer/pull/11 +[16]: https://github.com/rust-num/num-integer/pull/16 +[18]: https://github.com/rust-num/num-integer/pull/18 +[19]: https://github.com/rust-num/num-integer/pull/19 + +# Release 0.1.39 (2018-06-20) - [The new `Roots` trait provides `sqrt`, `cbrt`, and `nth_root` methods][9], calculating an `Integer`'s principal roots rounded toward zero. @@ -7,7 +29,7 @@ [9]: https://github.com/rust-num/num-integer/pull/9 -# Release 0.1.38 +# Release 0.1.38 (2018-05-11) - [Support for 128-bit integers is now automatically detected and enabled.][8] Setting the `i128` crate feature now causes the build script to panic if such @@ -17,7 +39,7 @@ [8]: https://github.com/rust-num/num-integer/pull/8 -# Release 0.1.37 +# Release 0.1.37 (2018-05-10) - [`Integer` is now implemented for `i128` and `u128`][7] starting with Rust 1.26, enabled by the new `i128` crate feature. @@ -26,7 +48,7 @@ [7]: https://github.com/rust-num/num-integer/pull/7 -# Release 0.1.36 +# Release 0.1.36 (2018-02-06) - [num-integer now has its own source repository][num-356] at [rust-num/num-integer][home]. - [Corrected the argument order documented in `Integer::is_multiple_of`][1] diff --git a/third_party/rust/num-integer/benches/gcd.rs b/third_party/rust/num-integer/benches/gcd.rs new file mode 100644 index 000000000000..082d5ee09d7b --- /dev/null +++ b/third_party/rust/num-integer/benches/gcd.rs @@ -0,0 +1,176 @@ +//! Benchmark comparing the current GCD implemtation against an older one. + +#![feature(test)] + +extern crate num_integer; +extern crate num_traits; +extern crate test; + +use num_integer::Integer; +use num_traits::{AsPrimitive, Bounded, Signed}; +use test::{black_box, Bencher}; + +trait GcdOld: Integer { + fn gcd_old(&self, other: &Self) -> Self; +} + +macro_rules! impl_gcd_old_for_isize { + ($T:ty) => { + impl GcdOld for $T { + /// Calculates the Greatest Common Divisor (GCD) of the number and + /// `other`. The result is always positive. + #[inline] + fn gcd_old(&self, other: &Self) -> Self { + // Use Stein's algorithm + let mut m = *self; + let mut n = *other; + if m == 0 || n == 0 { + return (m | n).abs(); + } + + // find common factors of 2 + let shift = (m | n).trailing_zeros(); + + // The algorithm needs positive numbers, but the minimum value + // can't be represented as a positive one. + // It's also a power of two, so the gcd can be + // calculated by bitshifting in that case + + // Assuming two's complement, the number created by the shift + // is positive for all numbers except gcd = abs(min value) + // The call to .abs() causes a panic in debug mode + if m == Self::min_value() || n == Self::min_value() { + return (1 << shift).abs(); + } + + // guaranteed to be positive now, rest like unsigned algorithm + m = m.abs(); + n = n.abs(); + + // divide n and m by 2 until odd + // m inside loop + n >>= n.trailing_zeros(); + + while m != 0 { + m >>= m.trailing_zeros(); + if n > m { + std::mem::swap(&mut n, &mut m) + } + m -= n; + } + + n << shift + } + } + }; +} + +impl_gcd_old_for_isize!(i8); +impl_gcd_old_for_isize!(i16); +impl_gcd_old_for_isize!(i32); +impl_gcd_old_for_isize!(i64); +impl_gcd_old_for_isize!(isize); +impl_gcd_old_for_isize!(i128); + +macro_rules! impl_gcd_old_for_usize { + ($T:ty) => { + impl GcdOld for $T { + /// Calculates the Greatest Common Divisor (GCD) of the number and + /// `other`. The result is always positive. + #[inline] + fn gcd_old(&self, other: &Self) -> Self { + // Use Stein's algorithm + let mut m = *self; + let mut n = *other; + if m == 0 || n == 0 { + return m | n; + } + + // find common factors of 2 + let shift = (m | n).trailing_zeros(); + + // divide n and m by 2 until odd + // m inside loop + n >>= n.trailing_zeros(); + + while m != 0 { + m >>= m.trailing_zeros(); + if n > m { + std::mem::swap(&mut n, &mut m) + } + m -= n; + } + + n << shift + } + } + }; +} + +impl_gcd_old_for_usize!(u8); +impl_gcd_old_for_usize!(u16); +impl_gcd_old_for_usize!(u32); +impl_gcd_old_for_usize!(u64); +impl_gcd_old_for_usize!(usize); +impl_gcd_old_for_usize!(u128); + +/// Return an iterator that yields all Fibonacci numbers fitting into a u128. +fn fibonacci() -> impl Iterator { + (0..185).scan((0, 1), |&mut (ref mut a, ref mut b), _| { + let tmp = *a; + *a = *b; + *b += tmp; + Some(*b) + }) +} + +fn run_bench(b: &mut Bencher, gcd: fn(&T, &T) -> T) +where + T: AsPrimitive, + u128: AsPrimitive, +{ + let max_value: u128 = T::max_value().as_(); + let pairs: Vec<(T, T)> = fibonacci() + .collect::>() + .windows(2) + .filter(|&pair| pair[0] <= max_value && pair[1] <= max_value) + .map(|pair| (pair[0].as_(), pair[1].as_())) + .collect(); + b.iter(|| { + for &(ref m, ref n) in &pairs { + black_box(gcd(m, n)); + } + }); +} + +macro_rules! bench_gcd { + ($T:ident) => { + mod $T { + use crate::{run_bench, GcdOld}; + use num_integer::Integer; + use test::Bencher; + + #[bench] + fn bench_gcd(b: &mut Bencher) { + run_bench(b, $T::gcd); + } + + #[bench] + fn bench_gcd_old(b: &mut Bencher) { + run_bench(b, $T::gcd_old); + } + } + }; +} + +bench_gcd!(u8); +bench_gcd!(u16); +bench_gcd!(u32); +bench_gcd!(u64); +bench_gcd!(u128); + +bench_gcd!(i8); +bench_gcd!(i16); +bench_gcd!(i32); +bench_gcd!(i64); +bench_gcd!(i128); diff --git a/third_party/rust/num-integer/benches/roots.rs b/third_party/rust/num-integer/benches/roots.rs index 3ca801581577..7f672786a572 100644 --- a/third_party/rust/num-integer/benches/roots.rs +++ b/third_party/rust/num-integer/benches/roots.rs @@ -13,11 +13,7 @@ use test::{black_box, Bencher}; trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} -impl BenchInteger for T -where - T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static, -{ -} +impl BenchInteger for T where T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} fn bench(b: &mut Bencher, v: &[T], f: F, n: u32) where diff --git a/third_party/rust/num-integer/bors.toml b/third_party/rust/num-integer/bors.toml deleted file mode 100644 index ca08e818bf3e..000000000000 --- a/third_party/rust/num-integer/bors.toml +++ /dev/null @@ -1,3 +0,0 @@ -status = [ - "continuous-integration/travis-ci/push", -] diff --git a/third_party/rust/num-integer/build.rs b/third_party/rust/num-integer/build.rs index fd60866558c3..15590bbc12bb 100644 --- a/third_party/rust/num-integer/build.rs +++ b/third_party/rust/num-integer/build.rs @@ -1,35 +1,14 @@ +extern crate autocfg; + use std::env; -use std::io::Write; -use std::process::{Command, Stdio}; fn main() { - if probe("fn main() { 0i128; }") { + let ac = autocfg::new(); + if ac.probe_type("i128") { println!("cargo:rustc-cfg=has_i128"); } else if env::var_os("CARGO_FEATURE_I128").is_some() { panic!("i128 support was not detected!"); } -} - -/// Test if a code snippet can be compiled -fn probe(code: &str) -> bool { - let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); - let out_dir = env::var_os("OUT_DIR").expect("environment variable OUT_DIR"); - - let mut child = Command::new(rustc) - .arg("--out-dir") - .arg(out_dir) - .arg("--emit=obj") - .arg("-") - .stdin(Stdio::piped()) - .spawn() - .expect("rustc probe"); - - child - .stdin - .as_mut() - .expect("rustc stdin") - .write_all(code.as_bytes()) - .expect("write rustc stdin"); - - child.wait().expect("rustc probe").success() + + autocfg::rerun_path(file!()); } diff --git a/third_party/rust/num-integer/ci/rustup.sh b/third_party/rust/num-integer/ci/rustup.sh deleted file mode 100755 index e82ece76d7a6..000000000000 --- a/third_party/rust/num-integer/ci/rustup.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# Use rustup to locally run the same suite of tests as .travis.yml. -# (You should first install/update 1.8.0, stable, beta, and nightly.) - -set -ex - -export TRAVIS_RUST_VERSION -for TRAVIS_RUST_VERSION in 1.8.0 1.15.0 1.20.0 stable beta nightly; do - run="rustup run $TRAVIS_RUST_VERSION" - $run cargo build --verbose - $run $PWD/ci/test_full.sh -done diff --git a/third_party/rust/num-integer/ci/test_full.sh b/third_party/rust/num-integer/ci/test_full.sh deleted file mode 100755 index e7c2549e8da0..000000000000 --- a/third_party/rust/num-integer/ci/test_full.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -set -ex - -echo Testing num-integer on rustc ${TRAVIS_RUST_VERSION} - -# num-integer should build and test everywhere. -cargo build --verbose -cargo test --verbose - -# test `no_std` -cargo build --verbose --no-default-features -cargo test --verbose --no-default-features - -# test `i128` -if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable)$ ]]; then - cargo build --verbose --features=i128 - cargo test --verbose --features=i128 -fi - -if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then - cargo test --verbose --all-features --benches -fi diff --git a/third_party/rust/num-integer/src/lib.rs b/third_party/rust/num-integer/src/lib.rs index 57f4c855d035..aa12ba68c4bb 100644 --- a/third_party/rust/num-integer/src/lib.rs +++ b/third_party/rust/num-integer/src/lib.rs @@ -15,21 +15,20 @@ //! The `num-integer` crate is tested for rustc 1.8 and greater. #![doc(html_root_url = "https://docs.rs/num-integer/0.1")] - #![no_std] #[cfg(feature = "std")] extern crate std; extern crate num_traits as traits; -use core::ops::Add; use core::mem; +use core::ops::Add; -use traits::{Num, Signed}; +use traits::{Num, Signed, Zero}; mod roots; pub use roots::Roots; -pub use roots::{sqrt, cbrt, nth_root}; +pub use roots::{cbrt, nth_root, sqrt}; pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// Floored integer division. @@ -74,6 +73,31 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// ~~~ fn mod_floor(&self, other: &Self) -> Self; + /// Ceiled integer division. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(( 8).div_ceil( &3), 3); + /// assert_eq!(( 8).div_ceil(&-3), -2); + /// assert_eq!((-8).div_ceil( &3), -2); + /// assert_eq!((-8).div_ceil(&-3), 3); + /// + /// assert_eq!(( 1).div_ceil( &2), 1); + /// assert_eq!(( 1).div_ceil(&-2), 0); + /// assert_eq!((-1).div_ceil( &2), 0); + /// assert_eq!((-1).div_ceil(&-2), 1); + /// ~~~ + fn div_ceil(&self, other: &Self) -> Self { + let (q, r) = self.div_mod_floor(other); + if r.is_zero() { + q + } else { + q + Self::one() + } + } + /// Greatest Common Divisor (GCD). /// /// # Examples @@ -93,9 +117,93 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// # use num_integer::Integer; /// assert_eq!(7.lcm(&3), 21); /// assert_eq!(2.lcm(&4), 4); + /// assert_eq!(0.lcm(&0), 0); /// ~~~ fn lcm(&self, other: &Self) -> Self; + /// Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) together. + /// + /// Potentially more efficient than calling `gcd` and `lcm` + /// individually for identical inputs. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(10.gcd_lcm(&4), (2, 20)); + /// assert_eq!(8.gcd_lcm(&9), (1, 72)); + /// ~~~ + #[inline] + fn gcd_lcm(&self, other: &Self) -> (Self, Self) { + (self.gcd(other), self.lcm(other)) + } + + /// Greatest common divisor and Bézout coefficients. + /// + /// # Examples + /// + /// ~~~ + /// # extern crate num_integer; + /// # extern crate num_traits; + /// # fn main() { + /// # use num_integer::{ExtendedGcd, Integer}; + /// # use num_traits::NumAssign; + /// fn check(a: A, b: A) -> bool { + /// let ExtendedGcd { gcd, x, y, .. } = a.extended_gcd(&b); + /// gcd == x * a + y * b + /// } + /// assert!(check(10isize, 4isize)); + /// assert!(check(8isize, 9isize)); + /// # } + /// ~~~ + #[inline] + fn extended_gcd(&self, other: &Self) -> ExtendedGcd + where + Self: Clone, + { + let mut s = (Self::zero(), Self::one()); + let mut t = (Self::one(), Self::zero()); + let mut r = (other.clone(), self.clone()); + + while !r.0.is_zero() { + let q = r.1.clone() / r.0.clone(); + let f = |mut r: (Self, Self)| { + mem::swap(&mut r.0, &mut r.1); + r.0 = r.0 - q.clone() * r.1.clone(); + r + }; + r = f(r); + s = f(s); + t = f(t); + } + + if r.1 >= Self::zero() { + ExtendedGcd { + gcd: r.1, + x: s.1, + y: t.1, + _hidden: (), + } + } else { + ExtendedGcd { + gcd: Self::zero() - r.1, + x: Self::zero() - s.1, + y: Self::zero() - t.1, + _hidden: (), + } + } + } + + /// Greatest common divisor, least common multiple, and Bézout coefficients. + #[inline] + fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd, Self) + where + Self: Clone + Signed, + { + (self.extended_gcd(other), self.lcm(other)) + } + /// Deprecated, use `is_multiple_of` instead. fn divides(&self, other: &Self) -> bool; @@ -172,6 +280,80 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { fn div_mod_floor(&self, other: &Self) -> (Self, Self) { (self.div_floor(other), self.mod_floor(other)) } + + /// Rounds up to nearest multiple of argument. + /// + /// # Notes + /// + /// For signed types, `a.next_multiple_of(b) = a.prev_multiple_of(b.neg())`. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(( 16).next_multiple_of(& 8), 16); + /// assert_eq!(( 23).next_multiple_of(& 8), 24); + /// assert_eq!(( 16).next_multiple_of(&-8), 16); + /// assert_eq!(( 23).next_multiple_of(&-8), 16); + /// assert_eq!((-16).next_multiple_of(& 8), -16); + /// assert_eq!((-23).next_multiple_of(& 8), -16); + /// assert_eq!((-16).next_multiple_of(&-8), -16); + /// assert_eq!((-23).next_multiple_of(&-8), -24); + /// ~~~ + #[inline] + fn next_multiple_of(&self, other: &Self) -> Self + where + Self: Clone, + { + let m = self.mod_floor(other); + self.clone() + + if m.is_zero() { + Self::zero() + } else { + other.clone() - m + } + } + + /// Rounds down to nearest multiple of argument. + /// + /// # Notes + /// + /// For signed types, `a.prev_multiple_of(b) = a.next_multiple_of(b.neg())`. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(( 16).prev_multiple_of(& 8), 16); + /// assert_eq!(( 23).prev_multiple_of(& 8), 16); + /// assert_eq!(( 16).prev_multiple_of(&-8), 16); + /// assert_eq!(( 23).prev_multiple_of(&-8), 24); + /// assert_eq!((-16).prev_multiple_of(& 8), -16); + /// assert_eq!((-23).prev_multiple_of(& 8), -24); + /// assert_eq!((-16).prev_multiple_of(&-8), -16); + /// assert_eq!((-23).prev_multiple_of(&-8), -16); + /// ~~~ + #[inline] + fn prev_multiple_of(&self, other: &Self) -> Self + where + Self: Clone, + { + self.clone() - self.mod_floor(other) + } +} + +/// Greatest common divisor and Bézout coefficients +/// +/// ```no_build +/// let e = isize::extended_gcd(a, b); +/// assert_eq!(e.gcd, e.x*a + e.y*b); +/// ``` +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ExtendedGcd { + pub gcd: A, + pub x: A, + pub y: A, + _hidden: (), } /// Simultaneous integer division and modulus @@ -194,6 +376,11 @@ pub fn mod_floor(x: T, y: T) -> T { pub fn div_mod_floor(x: T, y: T) -> (T, T) { x.div_mod_floor(&y) } +/// Ceiled integer division +#[inline] +pub fn div_ceil(x: T, y: T) -> T { + x.div_ceil(&y) +} /// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The /// result is always positive. @@ -207,18 +394,26 @@ pub fn lcm(x: T, y: T) -> T { x.lcm(&y) } +/// Calculates the Greatest Common Divisor (GCD) and +/// Lowest Common Multiple (LCM) of the number and `other`. +#[inline(always)] +pub fn gcd_lcm(x: T, y: T) -> (T, T) { + x.gcd_lcm(&y) +} + macro_rules! impl_integer_for_isize { - ($T:ty, $test_mod:ident) => ( + ($T:ty, $test_mod:ident) => { impl Integer for $T { /// Floored integer division #[inline] fn div_floor(&self, other: &Self) -> Self { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.div_rem(other) { - (d, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => d - 1, - (d, _) => d, + let (d, r) = self.div_rem(other); + if (r > 0 && *other < 0) || (r < 0 && *other > 0) { + d - 1 + } else { + d } } @@ -227,10 +422,11 @@ macro_rules! impl_integer_for_isize { fn mod_floor(&self, other: &Self) -> Self { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match *self % *other { - r if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => r + *other, - r => r, + let r = *self % *other; + if (r > 0 && *other < 0) || (r < 0 && *other > 0) { + r + *other + } else { + r } } @@ -239,10 +435,21 @@ macro_rules! impl_integer_for_isize { fn div_mod_floor(&self, other: &Self) -> (Self, Self) { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.div_rem(other) { - (d, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => (d - 1, r + *other), - (d, r) => (d, r), + let (d, r) = self.div_rem(other); + if (r > 0 && *other < 0) || (r < 0 && *other > 0) { + (d - 1, r + *other) + } else { + (d, r) + } + } + + #[inline] + fn div_ceil(&self, other: &Self) -> Self { + let (d, r) = self.div_rem(other); + if (r > 0 && *other > 0) || (r < 0 && *other < 0) { + d + 1 + } else { + d } } @@ -253,7 +460,9 @@ macro_rules! impl_integer_for_isize { // Use Stein's algorithm let mut m = *self; let mut n = *other; - if m == 0 || n == 0 { return (m | n).abs() } + if m == 0 || n == 0 { + return (m | n).abs(); + } // find common factors of 2 let shift = (m | n).trailing_zeros(); @@ -267,7 +476,7 @@ macro_rules! impl_integer_for_isize { // is positive for all numbers except gcd = abs(min value) // The call to .abs() causes a panic in debug mode if m == Self::min_value() || n == Self::min_value() { - return (1 << shift).abs() + return (1 << shift).abs(); } // guaranteed to be positive now, rest like unsigned algorithm @@ -275,24 +484,51 @@ macro_rules! impl_integer_for_isize { n = n.abs(); // divide n and m by 2 until odd - // m inside loop + m >>= m.trailing_zeros(); n >>= n.trailing_zeros(); - while m != 0 { - m >>= m.trailing_zeros(); - if n > m { mem::swap(&mut n, &mut m) } - m -= n; + while m != n { + if m > n { + m -= n; + m >>= m.trailing_zeros(); + } else { + n -= m; + n >>= n.trailing_zeros(); + } } + m << shift + } - n << shift + #[inline] + fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd, Self) { + let egcd = self.extended_gcd(other); + // should not have to recalculate abs + let lcm = if egcd.gcd.is_zero() { + Self::zero() + } else { + (*self * (*other / egcd.gcd)).abs() + }; + (egcd, lcm) } /// Calculates the Lowest Common Multiple (LCM) of the number and /// `other`. #[inline] fn lcm(&self, other: &Self) -> Self { + self.gcd_lcm(other).1 + } + + /// Calculates the Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) of the number and `other`. + #[inline] + fn gcd_lcm(&self, other: &Self) -> (Self, Self) { + if self.is_zero() && other.is_zero() { + return (Self::zero(), Self::zero()); + } + let gcd = self.gcd(other); // should not have to recalculate abs - (*self * (*other / self.gcd(other))).abs() + let lcm = (*self * (*other / gcd)).abs(); + (gcd, lcm) } /// Deprecated, use `is_multiple_of` instead. @@ -309,11 +545,15 @@ macro_rules! impl_integer_for_isize { /// Returns `true` if the number is divisible by `2` #[inline] - fn is_even(&self) -> bool { (*self) & 1 == 0 } + fn is_even(&self) -> bool { + (*self) & 1 == 0 + } /// Returns `true` if the number is not divisible by `2` #[inline] - fn is_odd(&self) -> bool { !self.is_even() } + fn is_odd(&self) -> bool { + !self.is_even() + } /// Simultaneous truncated integer division and modulus. #[inline] @@ -324,8 +564,8 @@ macro_rules! impl_integer_for_isize { #[cfg(test)] mod $test_mod { - use Integer; use core::mem; + use Integer; /// Checks that the division rule holds for: /// @@ -333,14 +573,14 @@ macro_rules! impl_integer_for_isize { /// - `d`: denominator (divisor) /// - `qr`: quotient and remainder #[cfg(test)] - fn test_division_rule((n,d): ($T, $T), (q,r): ($T, $T)) { + fn test_division_rule((n, d): ($T, $T), (q, r): ($T, $T)) { assert_eq!(d * q + r, n); } #[test] fn test_div_rem() { - fn test_nd_dr(nd: ($T,$T), qr: ($T,$T)) { - let (n,d) = nd; + fn test_nd_dr(nd: ($T, $T), qr: ($T, $T)) { + let (n, d) = nd; let separate_div_rem = (n / d, n % d); let combined_div_rem = n.div_rem(&d); @@ -351,21 +591,21 @@ macro_rules! impl_integer_for_isize { test_division_rule(nd, combined_div_rem); } - test_nd_dr(( 8, 3), ( 2, 2)); - test_nd_dr(( 8, -3), (-2, 2)); - test_nd_dr((-8, 3), (-2, -2)); - test_nd_dr((-8, -3), ( 2, -2)); + test_nd_dr((8, 3), (2, 2)); + test_nd_dr((8, -3), (-2, 2)); + test_nd_dr((-8, 3), (-2, -2)); + test_nd_dr((-8, -3), (2, -2)); - test_nd_dr(( 1, 2), ( 0, 1)); - test_nd_dr(( 1, -2), ( 0, 1)); - test_nd_dr((-1, 2), ( 0, -1)); - test_nd_dr((-1, -2), ( 0, -1)); + test_nd_dr((1, 2), (0, 1)); + test_nd_dr((1, -2), (0, 1)); + test_nd_dr((-1, 2), (0, -1)); + test_nd_dr((-1, -2), (0, -1)); } #[test] fn test_div_mod_floor() { - fn test_nd_dm(nd: ($T,$T), dm: ($T,$T)) { - let (n,d) = nd; + fn test_nd_dm(nd: ($T, $T), dm: ($T, $T)) { + let (n, d) = nd; let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d)); let combined_div_mod_floor = n.div_mod_floor(&d); @@ -376,15 +616,15 @@ macro_rules! impl_integer_for_isize { test_division_rule(nd, combined_div_mod_floor); } - test_nd_dm(( 8, 3), ( 2, 2)); - test_nd_dm(( 8, -3), (-3, -1)); - test_nd_dm((-8, 3), (-3, 1)); - test_nd_dm((-8, -3), ( 2, -2)); + test_nd_dm((8, 3), (2, 2)); + test_nd_dm((8, -3), (-3, -1)); + test_nd_dm((-8, 3), (-3, 1)); + test_nd_dm((-8, -3), (2, -2)); - test_nd_dm(( 1, 2), ( 0, 1)); - test_nd_dm(( 1, -2), (-1, -1)); - test_nd_dm((-1, 2), (-1, 1)); - test_nd_dm((-1, -2), ( 0, -1)); + test_nd_dm((1, 2), (0, 1)); + test_nd_dm((1, -2), (-1, -1)); + test_nd_dm((-1, 2), (-1, 1)); + test_nd_dm((-1, -2), (0, -1)); } #[test] @@ -414,7 +654,7 @@ macro_rules! impl_integer_for_isize { // for i8 for i in -127..127 { for j in -127..127 { - assert_eq!(euclidean_gcd(i,j), i.gcd(&j)); + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); } } @@ -422,7 +662,7 @@ macro_rules! impl_integer_for_isize { // FIXME: Use inclusive ranges for above loop when implemented let i = 127; for j in -127..127 { - assert_eq!(euclidean_gcd(i,j), i.gcd(&j)); + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); } assert_eq!(127.gcd(&127), 127); } @@ -473,6 +713,49 @@ macro_rules! impl_integer_for_isize { assert_eq!((11 as $T).lcm(&5), 55 as $T); } + #[test] + fn test_gcd_lcm() { + use core::iter::once; + for i in once(0) + .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) + .chain(once(-128)) + { + for j in once(0) + .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) + .chain(once(-128)) + { + assert_eq!(i.gcd_lcm(&j), (i.gcd(&j), i.lcm(&j))); + } + } + } + + #[test] + fn test_extended_gcd_lcm() { + use core::fmt::Debug; + use traits::NumAssign; + use ExtendedGcd; + + fn check(a: A, b: A) { + let ExtendedGcd { gcd, x, y, .. } = a.extended_gcd(&b); + assert_eq!(gcd, x * a + y * b); + } + + use core::iter::once; + for i in once(0) + .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) + .chain(once(-128)) + { + for j in once(0) + .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) + .chain(once(-128)) + { + check(i, j); + let (ExtendedGcd { gcd, .. }, lcm) = i.extended_gcd_lcm(&j); + assert_eq!((gcd, lcm), (i.gcd(&j), i.lcm(&j))); + } + } + } + #[test] fn test_even() { assert_eq!((-4 as $T).is_even(), true); @@ -499,7 +782,7 @@ macro_rules! impl_integer_for_isize { assert_eq!((4 as $T).is_odd(), false); } } - ) + }; } impl_integer_for_isize!(i8, test_integer_i8); @@ -511,7 +794,7 @@ impl_integer_for_isize!(isize, test_integer_isize); impl_integer_for_isize!(i128, test_integer_i128); macro_rules! impl_integer_for_usize { - ($T:ty, $test_mod:ident) => ( + ($T:ty, $test_mod:ident) => { impl Integer for $T { /// Unsigned integer division. Returns the same result as `div` (`/`). #[inline] @@ -525,34 +808,68 @@ macro_rules! impl_integer_for_usize { *self % *other } + #[inline] + fn div_ceil(&self, other: &Self) -> Self { + *self / *other + (0 != *self % *other) as Self + } + /// Calculates the Greatest Common Divisor (GCD) of the number and `other` #[inline] fn gcd(&self, other: &Self) -> Self { // Use Stein's algorithm let mut m = *self; let mut n = *other; - if m == 0 || n == 0 { return m | n } + if m == 0 || n == 0 { + return m | n; + } // find common factors of 2 let shift = (m | n).trailing_zeros(); // divide n and m by 2 until odd - // m inside loop + m >>= m.trailing_zeros(); n >>= n.trailing_zeros(); - while m != 0 { - m >>= m.trailing_zeros(); - if n > m { mem::swap(&mut n, &mut m) } - m -= n; + while m != n { + if m > n { + m -= n; + m >>= m.trailing_zeros(); + } else { + n -= m; + n >>= n.trailing_zeros(); + } } + m << shift + } - n << shift + #[inline] + fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd, Self) { + let egcd = self.extended_gcd(other); + // should not have to recalculate abs + let lcm = if egcd.gcd.is_zero() { + Self::zero() + } else { + *self * (*other / egcd.gcd) + }; + (egcd, lcm) } /// Calculates the Lowest Common Multiple (LCM) of the number and `other`. #[inline] fn lcm(&self, other: &Self) -> Self { - *self * (*other / self.gcd(other)) + self.gcd_lcm(other).1 + } + + /// Calculates the Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) of the number and `other`. + #[inline] + fn gcd_lcm(&self, other: &Self) -> (Self, Self) { + if self.is_zero() && other.is_zero() { + return (Self::zero(), Self::zero()); + } + let gcd = self.gcd(other); + let lcm = *self * (*other / gcd); + (gcd, lcm) } /// Deprecated, use `is_multiple_of` instead. @@ -588,8 +905,8 @@ macro_rules! impl_integer_for_usize { #[cfg(test)] mod $test_mod { - use Integer; use core::mem; + use Integer; #[test] fn test_div_mod_floor() { @@ -625,7 +942,7 @@ macro_rules! impl_integer_for_usize { for i in 0..255 { for j in 0..255 { - assert_eq!(euclidean_gcd(i,j), i.gcd(&j)); + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); } } @@ -633,7 +950,7 @@ macro_rules! impl_integer_for_usize { // FIXME: Use inclusive ranges for above loop when implemented let i = 255; for j in 0..255 { - assert_eq!(euclidean_gcd(i,j), i.gcd(&j)); + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); } assert_eq!(255.gcd(&255), 255); } @@ -648,6 +965,15 @@ macro_rules! impl_integer_for_usize { assert_eq!((15 as $T).lcm(&17), 255 as $T); } + #[test] + fn test_gcd_lcm() { + for i in (0..).take(256) { + for j in (0..).take(256) { + assert_eq!(i.gcd_lcm(&j), (i.gcd(&j), i.lcm(&j))); + } + } + } + #[test] fn test_is_multiple_of() { assert!((6 as $T).is_multiple_of(&(6 as $T))); @@ -673,7 +999,7 @@ macro_rules! impl_integer_for_usize { assert_eq!((4 as $T).is_odd(), false); } } - ) + }; } impl_integer_for_usize!(u8, test_integer_u8); @@ -692,7 +1018,8 @@ pub struct IterBinomial { } impl IterBinomial - where T: Integer, +where + T: Integer, { /// For a given n, iterate over all binomial coefficients binomial(n, k), for k=0...n. /// @@ -714,13 +1041,16 @@ impl IterBinomial /// For larger n, `T` should be a bigint type. pub fn new(n: T) -> IterBinomial { IterBinomial { - k: T::zero(), a: T::one(), n: n + k: T::zero(), + a: T::one(), + n: n, } } } impl Iterator for IterBinomial - where T: Integer + Clone +where + T: Integer + Clone, { type Item = T; @@ -732,7 +1062,7 @@ impl Iterator for IterBinomial multiply_and_divide( self.a.clone(), self.n.clone() - self.k.clone() + T::one(), - self.k.clone() + self.k.clone(), ) } else { T::one() @@ -748,7 +1078,7 @@ impl Iterator for IterBinomial fn multiply_and_divide(r: T, a: T, b: T) -> T { // See http://blog.plover.com/math/choose-2.html for the idea. let g = gcd(r.clone(), b.clone()); - r/g.clone() * (a / (b/g)) + r / g.clone() * (a / (b / g)) } /// Calculate the binomial coefficient. @@ -792,7 +1122,8 @@ pub fn binomial(mut n: T, k: T) -> T { /// Calculate the multinomial coefficient. pub fn multinomial(k: &[T]) -> T - where for<'a> T: Add<&'a T, Output = T> +where + for<'a> T: Add<&'a T, Output = T>, { let mut r = T::one(); let mut p = T::zero(); @@ -806,16 +1137,20 @@ pub fn multinomial(k: &[T]) -> T #[test] fn test_lcm_overflow() { macro_rules! check { - ($t:ty, $x:expr, $y:expr, $r:expr) => { { + ($t:ty, $x:expr, $y:expr, $r:expr) => {{ let x: $t = $x; let y: $t = $y; let o = x.checked_mul(y); - assert!(o.is_none(), - "sanity checking that {} input {} * {} overflows", - stringify!($t), x, y); + assert!( + o.is_none(), + "sanity checking that {} input {} * {} overflows", + stringify!($t), + x, + y + ); assert_eq!(x.lcm(&y), $r); assert_eq!(y.lcm(&x), $r); - } } + }}; } // Original bug (Issue #166) @@ -834,13 +1169,13 @@ fn test_lcm_overflow() { #[test] fn test_iter_binomial() { macro_rules! check_simple { - ($t:ty) => { { + ($t:ty) => {{ let n: $t = 3; let expected = [1, 3, 3, 1]; for (b, &e) in IterBinomial::new(n).zip(&expected) { assert_eq!(b, e); } - } } + }}; } check_simple!(u8); @@ -853,14 +1188,14 @@ fn test_iter_binomial() { check_simple!(i64); macro_rules! check_binomial { - ($t:ty, $n:expr) => { { + ($t:ty, $n:expr) => {{ let n: $t = $n; let mut k: $t = 0; for b in IterBinomial::new(n) { assert_eq!(b, binomial(n, k)); k += 1; } - } } + }}; } // Check the largest n for which there is no overflow. @@ -877,7 +1212,7 @@ fn test_iter_binomial() { #[test] fn test_binomial() { macro_rules! check { - ($t:ty, $x:expr, $y:expr, $r:expr) => { { + ($t:ty, $x:expr, $y:expr, $r:expr) => {{ let x: $t = $x; let y: $t = $y; let expected: $t = $r; @@ -885,7 +1220,7 @@ fn test_binomial() { if y <= x { assert_eq!(binomial(x, x - y), expected); } - } } + }}; } check!(u8, 9, 4, 126); check!(u8, 0, 0, 1); @@ -933,12 +1268,12 @@ fn test_binomial() { #[test] fn test_multinomial() { macro_rules! check_binomial { - ($t:ty, $k:expr) => { { + ($t:ty, $k:expr) => {{ let n: $t = $k.iter().fold(0, |acc, &x| acc + x); let k: &[$t] = $k; assert_eq!(k.len(), 2); assert_eq!(multinomial(k), binomial(n, k[0])); - } } + }}; } check_binomial!(u8, &[4, 5]); @@ -968,11 +1303,11 @@ fn test_multinomial() { check_binomial!(i64, &[4, 10]); macro_rules! check_multinomial { - ($t:ty, $k:expr, $r:expr) => { { + ($t:ty, $k:expr, $r:expr) => {{ let k: &[$t] = $k; let expected: $t = $r; assert_eq!(multinomial(k), expected); - } } + }}; } check_multinomial!(u8, &[2, 1, 2], 30); diff --git a/third_party/rust/num-integer/src/roots.rs b/third_party/rust/num-integer/src/roots.rs index 9bad31f9d78a..a9eec1a93cbe 100644 --- a/third_party/rust/num-integer/src/roots.rs +++ b/third_party/rust/num-integer/src/roots.rs @@ -202,170 +202,181 @@ fn log2(x: T) -> u32 { macro_rules! unsigned_roots { ($T:ident) => { impl Roots for $T { + #[inline] fn nth_root(&self, n: u32) -> Self { - // Specialize small roots - match n { - 0 => panic!("can't find a root of degree 0!"), - 1 => return *self, - 2 => return self.sqrt(), - 3 => return self.cbrt(), - _ => (), - } + fn go(a: $T, n: u32) -> $T { + // Specialize small roots + match n { + 0 => panic!("can't find a root of degree 0!"), + 1 => return a, + 2 => return a.sqrt(), + 3 => return a.cbrt(), + _ => (), + } - // The root of values less than 2ⁿ can only be 0 or 1. - if bits::<$T>() <= n || *self < (1 << n) { - return (*self > 0) as $T; - } + // The root of values less than 2ⁿ can only be 0 or 1. + if bits::<$T>() <= n || a < (1 << n) { + return (a > 0) as $T; + } - if bits::<$T>() > 64 { - // 128-bit division is slow, so do a bitwise `nth_root` until it's small enough. - return if *self <= core::u64::MAX as $T { - (*self as u64).nth_root(n) as $T - } else { - let lo = (self >> n).nth_root(n) << 1; - let hi = lo + 1; - // 128-bit `checked_mul` also involves division, but we can't always - // compute `hiⁿ` without risking overflow. Try to avoid it though... - if hi.next_power_of_two().trailing_zeros() * n >= bits::<$T>() { - match checked_pow(hi, n as usize) { - Some(x) if x <= *self => hi, - _ => lo, - } + if bits::<$T>() > 64 { + // 128-bit division is slow, so do a bitwise `nth_root` until it's small enough. + return if a <= core::u64::MAX as $T { + (a as u64).nth_root(n) as $T } else { - if hi.pow(n) <= *self { + let lo = (a >> n).nth_root(n) << 1; + let hi = lo + 1; + // 128-bit `checked_mul` also involves division, but we can't always + // compute `hiⁿ` without risking overflow. Try to avoid it though... + if hi.next_power_of_two().trailing_zeros() * n >= bits::<$T>() { + match checked_pow(hi, n as usize) { + Some(x) if x <= a => hi, + _ => lo, + } + } else { + if hi.pow(n) <= a { + hi + } else { + lo + } + } + }; + } + + #[cfg(feature = "std")] + #[inline] + fn guess(x: $T, n: u32) -> $T { + // for smaller inputs, `f64` doesn't justify its cost. + if bits::<$T>() <= 32 || x <= core::u32::MAX as $T { + 1 << ((log2(x) + n - 1) / n) + } else { + ((x as f64).ln() / f64::from(n)).exp() as $T + } + } + + #[cfg(not(feature = "std"))] + #[inline] + fn guess(x: $T, n: u32) -> $T { + 1 << ((log2(x) + n - 1) / n) + } + + // https://en.wikipedia.org/wiki/Nth_root_algorithm + let n1 = n - 1; + let next = |x: $T| { + let y = match checked_pow(x, n1 as usize) { + Some(ax) => a / ax, + None => 0, + }; + (y + x * n1 as $T) / n as $T + }; + fixpoint(guess(a, n), next) + } + go(*self, n) + } + + #[inline] + fn sqrt(&self) -> Self { + fn go(a: $T) -> $T { + if bits::<$T>() > 64 { + // 128-bit division is slow, so do a bitwise `sqrt` until it's small enough. + return if a <= core::u64::MAX as $T { + (a as u64).sqrt() as $T + } else { + let lo = (a >> 2u32).sqrt() << 1; + let hi = lo + 1; + if hi * hi <= a { hi } else { lo } - } - }; - } - - #[cfg(feature = "std")] - #[inline] - fn guess(x: $T, n: u32) -> $T { - // for smaller inputs, `f64` doesn't justify its cost. - if bits::<$T>() <= 32 || x <= core::u32::MAX as $T { - 1 << ((log2(x) + n - 1) / n) - } else { - ((x as f64).ln() / f64::from(n)).exp() as $T + }; } - } - #[cfg(not(feature = "std"))] - #[inline] - fn guess(x: $T, n: u32) -> $T { - 1 << ((log2(x) + n - 1) / n) - } + if a < 4 { + return (a > 0) as $T; + } - // https://en.wikipedia.org/wiki/Nth_root_algorithm - let n1 = n - 1; - let next = |x: $T| { - let y = match checked_pow(x, n1 as usize) { - Some(ax) => self / ax, - None => 0, - }; - (y + x * n1 as $T) / n as $T - }; - fixpoint(guess(*self, n), next) - } - - fn sqrt(&self) -> Self { - if bits::<$T>() > 64 { - // 128-bit division is slow, so do a bitwise `sqrt` until it's small enough. - // https://en.wikipedia.org/wiki/Integer_square_root#Using_bitwise_operations - return if *self <= core::u64::MAX as $T { - (*self as u64).sqrt() as $T - } else { - let lo = (self >> 2u32).sqrt() << 1; - let hi = lo + 1; - if hi * hi <= *self { - hi - } else { - lo - } - }; - } - - if *self < 4 { - return (*self > 0) as Self; - } - - #[cfg(feature = "std")] - #[inline] - fn guess(x: $T) -> $T { - (x as f64).sqrt() as $T - } - - #[cfg(not(feature = "std"))] - #[inline] - fn guess(x: $T) -> $T { - 1 << ((log2(x) + 1) / 2) - } - - // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method - let next = |x: $T| (self / x + x) >> 1; - fixpoint(guess(*self), next) + #[cfg(feature = "std")] + #[inline] + fn guess(x: $T) -> $T { + (x as f64).sqrt() as $T + } + + #[cfg(not(feature = "std"))] + #[inline] + fn guess(x: $T) -> $T { + 1 << ((log2(x) + 1) / 2) + } + + // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method + let next = |x: $T| (a / x + x) >> 1; + fixpoint(guess(a), next) + } + go(*self) } + #[inline] fn cbrt(&self) -> Self { - if bits::<$T>() > 64 { - // 128-bit division is slow, so do a bitwise `cbrt` until it's small enough. - return if *self <= core::u64::MAX as $T { - (*self as u64).cbrt() as $T - } else { - let lo = (self >> 3u32).cbrt() << 1; - let hi = lo + 1; - if hi * hi * hi <= *self { - hi + fn go(a: $T) -> $T { + if bits::<$T>() > 64 { + // 128-bit division is slow, so do a bitwise `cbrt` until it's small enough. + return if a <= core::u64::MAX as $T { + (a as u64).cbrt() as $T } else { - lo - } - }; - } - - if bits::<$T>() <= 32 { - // Implementation based on Hacker's Delight `icbrt2` - let mut x = *self; - let mut y2 = 0; - let mut y = 0; - let smax = bits::<$T>() / 3; - for s in (0..smax + 1).rev() { - let s = s * 3; - y2 *= 4; - y *= 2; - let b = 3 * (y2 + y) + 1; - if x >> s >= b { - x -= b << s; - y2 += 2 * y + 1; - y += 1; - } + let lo = (a >> 3u32).cbrt() << 1; + let hi = lo + 1; + if hi * hi * hi <= a { + hi + } else { + lo + } + }; } - return y; - } - if *self < 8 { - return (*self > 0) as Self; - } - if *self <= core::u32::MAX as $T { - return (*self as u32).cbrt() as $T; - } + if bits::<$T>() <= 32 { + // Implementation based on Hacker's Delight `icbrt2` + let mut x = a; + let mut y2 = 0; + let mut y = 0; + let smax = bits::<$T>() / 3; + for s in (0..smax + 1).rev() { + let s = s * 3; + y2 *= 4; + y *= 2; + let b = 3 * (y2 + y) + 1; + if x >> s >= b { + x -= b << s; + y2 += 2 * y + 1; + y += 1; + } + } + return y; + } - #[cfg(feature = "std")] - #[inline] - fn guess(x: $T) -> $T { - (x as f64).cbrt() as $T - } + if a < 8 { + return (a > 0) as $T; + } + if a <= core::u32::MAX as $T { + return (a as u32).cbrt() as $T; + } - #[cfg(not(feature = "std"))] - #[inline] - fn guess(x: $T) -> $T { - 1 << ((log2(x) + 2) / 3) - } + #[cfg(feature = "std")] + #[inline] + fn guess(x: $T) -> $T { + (x as f64).cbrt() as $T + } - // https://en.wikipedia.org/wiki/Cube_root#Numerical_methods - let next = |x: $T| (self / (x * x) + x * 2) / 3; - fixpoint(guess(*self), next) + #[cfg(not(feature = "std"))] + #[inline] + fn guess(x: $T) -> $T { + 1 << ((log2(x) + 2) / 3) + } + + // https://en.wikipedia.org/wiki/Cube_root#Numerical_methods + let next = |x: $T| (a / (x * x) + x * 2) / 3; + fixpoint(guess(a), next) + } + go(*self) } } }; diff --git a/third_party/rust/num-integer/tests/roots.rs b/third_party/rust/num-integer/tests/roots.rs index 85e97f327285..f85f9e021143 100644 --- a/third_party/rust/num-integer/tests/roots.rs +++ b/third_party/rust/num-integer/tests/roots.rs @@ -10,11 +10,7 @@ use std::mem; trait TestInteger: Roots + PrimInt + Debug + AsPrimitive + 'static {} -impl TestInteger for T -where - T: Roots + PrimInt + Debug + AsPrimitive + 'static, -{ -} +impl TestInteger for T where T: Roots + PrimInt + Debug + AsPrimitive + 'static {} /// Check that each root is correct /// diff --git a/third_party/rust/num-iter/.cargo-checksum.json b/third_party/rust/num-iter/.cargo-checksum.json index ec53015f36ad..0e326a29298b 100644 --- a/third_party/rust/num-iter/.cargo-checksum.json +++ b/third_party/rust/num-iter/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"c13da0848b07a604569216fdb430f87d43b83252055ab1f6e237fc4020897b2b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"f3be0ace34d626865f124c492483c30cadc3362c17aabefed45fa2686c67a070","RELEASES.md":"1031b964f47fd9c33e0249d1343b3292c830d7e2e6c8d88931dcbc25a20a0337","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","build.rs":"16de2aa57e754fc1526d0400b5d87a3f771296705fca54601aa598b6f74ded8f","ci/rustup.sh":"2aa9e89e4af81ed9da86bdcf7cdabe512287c877248783b69eed1eccf09ad6bb","ci/test_full.sh":"22ab0d413456c350a8a0e62e3614da628dad06eb4c923b4d162aef4cb47b9dd2","src/lib.rs":"e6b0f870ab6e741f15293b76b11e5bc01193aa8e08c13f5f67e2f85c3808636f"},"package":"af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"} \ No newline at end of file +{"files":{"Cargo.toml":"d0ebc04247f9987c23051c00f74e6c6f1df4f29147c5169ab61018865a7b1fcc","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"f3be0ace34d626865f124c492483c30cadc3362c17aabefed45fa2686c67a070","RELEASES.md":"b238cf5d43af9324607e4127efb55bd90f257d71b20c5d2d1108bcb2355560db","build.rs":"56d4fbb7a55750e61d2074df2735a31995c1decbd988c0e722926235e0fed487","src/lib.rs":"9aaa9570d8dc978fc8d653f30d8646bd9891062fd307726a84724bc86155c0f9"},"package":"76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e"} \ No newline at end of file diff --git a/third_party/rust/num-iter/Cargo.toml b/third_party/rust/num-iter/Cargo.toml index 3f01499a4ac9..c43a7d49d5f3 100644 --- a/third_party/rust/num-iter/Cargo.toml +++ b/third_party/rust/num-iter/Cargo.toml @@ -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,9 +12,10 @@ [package] name = "num-iter" -version = "0.1.37" +version = "0.1.39" authors = ["The Rust Project Developers"] build = "build.rs" +exclude = ["/ci/*", "/.travis.yml", "/bors.toml"] description = "External iterators for generic mathematics" homepage = "https://github.com/rust-num/num-iter" documentation = "https://docs.rs/num-iter" @@ -32,6 +33,8 @@ default-features = false [dependencies.num-traits] version = "0.2.4" default-features = false +[build-dependencies.autocfg] +version = "0.1.3" [features] default = ["std"] diff --git a/third_party/rust/num-iter/RELEASES.md b/third_party/rust/num-iter/RELEASES.md index c54fe521cead..e1e849c756d7 100644 --- a/third_party/rust/num-iter/RELEASES.md +++ b/third_party/rust/num-iter/RELEASES.md @@ -1,4 +1,18 @@ -# Release 0.1.37 +# Release 0.1.39 (2019-05-21) + +- [Fixed feature detection on `no_std` targets][11]. + +**Contributors**: @cuviper + +[11]: https://github.com/rust-num/num-iter/pull/11 + +# Release 0.1.38 (2019-05-20) + +- Maintenance update -- no functional changes. + +**Contributors**: @cuviper, @ignatenkobrain + +# Release 0.1.37 (2018-05-11) - [Support for 128-bit integers is now automatically detected and enabled.][5] Setting the `i128` crate feature now causes the build script to panic if such @@ -8,7 +22,7 @@ [5]: https://github.com/rust-num/num-iter/pull/5 -# Release 0.1.36 +# Release 0.1.36 (2018-05-10) - [The iterators are now implemented for `i128` and `u128`][7] starting with Rust 1.26, enabled by the new `i128` crate feature. @@ -17,7 +31,7 @@ [4]: https://github.com/rust-num/num-iter/pull/4 -# Release 0.1.35 +# Release 0.1.35 (2018-02-06) - [num-iter now has its own source repository][num-356] at [rust-num/num-iter][home]. - [There is now a `std` feature][2], enabled by default, along with the implication diff --git a/third_party/rust/num-iter/bors.toml b/third_party/rust/num-iter/bors.toml deleted file mode 100644 index ca08e818bf3e..000000000000 --- a/third_party/rust/num-iter/bors.toml +++ /dev/null @@ -1,3 +0,0 @@ -status = [ - "continuous-integration/travis-ci/push", -] diff --git a/third_party/rust/num-iter/build.rs b/third_party/rust/num-iter/build.rs index fd60866558c3..15590bbc12bb 100644 --- a/third_party/rust/num-iter/build.rs +++ b/third_party/rust/num-iter/build.rs @@ -1,35 +1,14 @@ +extern crate autocfg; + use std::env; -use std::io::Write; -use std::process::{Command, Stdio}; fn main() { - if probe("fn main() { 0i128; }") { + let ac = autocfg::new(); + if ac.probe_type("i128") { println!("cargo:rustc-cfg=has_i128"); } else if env::var_os("CARGO_FEATURE_I128").is_some() { panic!("i128 support was not detected!"); } -} - -/// Test if a code snippet can be compiled -fn probe(code: &str) -> bool { - let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); - let out_dir = env::var_os("OUT_DIR").expect("environment variable OUT_DIR"); - - let mut child = Command::new(rustc) - .arg("--out-dir") - .arg(out_dir) - .arg("--emit=obj") - .arg("-") - .stdin(Stdio::piped()) - .spawn() - .expect("rustc probe"); - - child - .stdin - .as_mut() - .expect("rustc stdin") - .write_all(code.as_bytes()) - .expect("write rustc stdin"); - - child.wait().expect("rustc probe").success() + + autocfg::rerun_path(file!()); } diff --git a/third_party/rust/num-iter/ci/rustup.sh b/third_party/rust/num-iter/ci/rustup.sh deleted file mode 100755 index e82ece76d7a6..000000000000 --- a/third_party/rust/num-iter/ci/rustup.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# Use rustup to locally run the same suite of tests as .travis.yml. -# (You should first install/update 1.8.0, stable, beta, and nightly.) - -set -ex - -export TRAVIS_RUST_VERSION -for TRAVIS_RUST_VERSION in 1.8.0 1.15.0 1.20.0 stable beta nightly; do - run="rustup run $TRAVIS_RUST_VERSION" - $run cargo build --verbose - $run $PWD/ci/test_full.sh -done diff --git a/third_party/rust/num-iter/ci/test_full.sh b/third_party/rust/num-iter/ci/test_full.sh deleted file mode 100755 index 2c5325eda85d..000000000000 --- a/third_party/rust/num-iter/ci/test_full.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -set -ex - -echo Testing num-iter on rustc ${TRAVIS_RUST_VERSION} - -# num-iter should build and test everywhere. -cargo build --verbose -cargo test --verbose - -# test `no_std` -cargo build --verbose --no-default-features -cargo test --verbose --no-default-features - -# test `i128` -if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable)$ ]]; then - cargo build --verbose --features=i128 - cargo test --verbose --features=i128 -fi diff --git a/third_party/rust/num-iter/src/lib.rs b/third_party/rust/num-iter/src/lib.rs index f4bac547fb25..9c96b6e6f605 100644 --- a/third_party/rust/num-iter/src/lib.rs +++ b/third_party/rust/num-iter/src/lib.rs @@ -15,25 +15,24 @@ //! The `num-iter` crate is tested for rustc 1.8 and greater. #![doc(html_root_url = "https://docs.rs/num-iter/0.1")] - #![no_std] #[cfg(feature = "std")] extern crate std; -extern crate num_traits as traits; extern crate num_integer as integer; +extern crate num_traits as traits; -use integer::Integer; -use traits::{Zero, One, CheckedAdd, ToPrimitive}; use core::ops::{Add, Sub}; use core::usize; +use integer::Integer; +use traits::{CheckedAdd, One, ToPrimitive, Zero}; /// An iterator over the range [start, stop) #[derive(Clone)] pub struct Range { state: A, stop: A, - one: A + one: A, } /// Returns an iterator over the given range [start, stop) (that is, starting @@ -51,9 +50,14 @@ pub struct Range { /// ``` #[inline] pub fn range(start: A, stop: A) -> Range - where A: Add + PartialOrd + Clone + One +where + A: Add + PartialOrd + Clone + One, { - Range{state: start, stop: stop, one: One::one()} + Range { + state: start, + stop: stop, + one: One::one(), + } } #[inline] @@ -82,7 +86,8 @@ fn unsigned(x: &T) -> Option { // FIXME: rust-lang/rust#10414: Unfortunate type bound impl Iterator for Range - where A: Add + PartialOrd + Clone + ToPrimitive +where + A: Add + PartialOrd + Clone + ToPrimitive, { type Item = A; @@ -113,7 +118,7 @@ impl Iterator for Range return match b.wrapping_sub(a).to_usize() { Some(len) => (len, Some(len)), None => (usize::MAX, None), - } + }; } } @@ -125,7 +130,8 @@ impl Iterator for Range /// `Integer` is required to ensure the range will be the same regardless of /// the direction it is consumed. impl DoubleEndedIterator for Range - where A: Integer + Clone + ToPrimitive +where + A: Integer + Clone + ToPrimitive, { #[inline] fn next_back(&mut self) -> Option { @@ -148,13 +154,18 @@ pub struct RangeInclusive { /// Return an iterator over the range [start, stop] #[inline] pub fn range_inclusive(start: A, stop: A) -> RangeInclusive - where A: Add + PartialOrd + Clone + One +where + A: Add + PartialOrd + Clone + One, { - RangeInclusive{range: range(start, stop), done: false} + RangeInclusive { + range: range(start, stop), + done: false, + } } impl Iterator for RangeInclusive - where A: Add + PartialOrd + Clone + ToPrimitive +where + A: Add + PartialOrd + Clone + ToPrimitive, { type Item = A; @@ -182,7 +193,7 @@ impl Iterator for RangeInclusive let lo = lo.saturating_add(1); let hi = match hi { Some(x) => x.checked_add(1), - None => None + None => None, }; (lo, hi) } @@ -190,7 +201,8 @@ impl Iterator for RangeInclusive } impl DoubleEndedIterator for RangeInclusive - where A: Sub + Integer + Clone + ToPrimitive +where + A: Sub + Integer + Clone + ToPrimitive, { #[inline] fn next_back(&mut self) -> Option { @@ -219,14 +231,21 @@ pub struct RangeStep { /// Return an iterator over the range [start, stop) by `step`. It handles overflow by stopping. #[inline] pub fn range_step(start: A, stop: A, step: A) -> RangeStep - where A: CheckedAdd + PartialOrd + Clone + Zero +where + A: CheckedAdd + PartialOrd + Clone + Zero, { let rev = step < Zero::zero(); - RangeStep{state: start, stop: stop, step: step, rev: rev} + RangeStep { + state: start, + stop: stop, + step: step, + rev: rev, + } } impl Iterator for RangeStep - where A: CheckedAdd + PartialOrd + Clone +where + A: CheckedAdd + PartialOrd + Clone, { type Item = A; @@ -236,7 +255,7 @@ impl Iterator for RangeStep let result = self.state.clone(); match self.state.checked_add(&self.step) { Some(x) => self.state = x, - None => self.state = self.stop.clone() + None => self.state = self.stop.clone(), } Some(result) } else { @@ -258,25 +277,34 @@ pub struct RangeStepInclusive { /// Return an iterator over the range [start, stop] by `step`. It handles overflow by stopping. #[inline] pub fn range_step_inclusive(start: A, stop: A, step: A) -> RangeStepInclusive - where A: CheckedAdd + PartialOrd + Clone + Zero +where + A: CheckedAdd + PartialOrd + Clone + Zero, { let rev = step < Zero::zero(); - RangeStepInclusive{state: start, stop: stop, step: step, rev: rev, done: false} + RangeStepInclusive { + state: start, + stop: stop, + step: step, + rev: rev, + done: false, + } } impl Iterator for RangeStepInclusive - where A: CheckedAdd + PartialOrd + Clone + PartialEq +where + A: CheckedAdd + PartialOrd + Clone + PartialEq, { type Item = A; #[inline] fn next(&mut self) -> Option { - if !self.done && ((self.rev && self.state >= self.stop) || - (!self.rev && self.state <= self.stop)) { + if !self.done + && ((self.rev && self.state >= self.stop) || (!self.rev && self.state <= self.stop)) + { let result = self.state.clone(); match self.state.checked_add(&self.step) { Some(x) => self.state = x, - None => self.done = true + None => self.done = true, } Some(result) } else { @@ -287,10 +315,10 @@ impl Iterator for RangeStepInclusive #[cfg(test)] mod tests { - use core::{isize, usize}; - use core::ops::{Add, Mul}; use core::cmp::Ordering; use core::iter; + use core::ops::{Add, Mul}; + use core::{isize, usize}; use traits::{One, ToPrimitive}; #[test] @@ -299,8 +327,12 @@ mod tests { struct Foo; impl ToPrimitive for Foo { - fn to_i64(&self) -> Option { None } - fn to_u64(&self) -> Option { None } + fn to_i64(&self) -> Option { + None + } + fn to_u64(&self) -> Option { + None + } } impl Add for Foo { @@ -343,12 +375,9 @@ mod tests { } } - assert!(super::range(0, 5) - .eq([0, 1, 2, 3, 4].iter().cloned())); - assert!(super::range(-10, -1) - .eq([-10, -9, -8, -7, -6, -5, -4, -3, -2].iter().cloned())); - assert!(super::range(0, 5).rev() - .eq([4, 3, 2, 1, 0].iter().cloned())); + assert!(super::range(0, 5).eq([0, 1, 2, 3, 4].iter().cloned())); + assert!(super::range(-10, -1).eq([-10, -9, -8, -7, -6, -5, -4, -3, -2].iter().cloned())); + assert!(super::range(0, 5).rev().eq([4, 3, 2, 1, 0].iter().cloned())); assert_eq!(super::range(200, -5).count(), 0); assert_eq!(super::range(200, -5).rev().count(), 0); assert_eq!(super::range(200, 200).count(), 0); @@ -356,9 +385,15 @@ mod tests { assert_eq!(super::range(0, 100).size_hint(), (100, Some(100))); // this test is only meaningful when sizeof usize < sizeof u64 - assert_eq!(super::range(usize::MAX - 1, usize::MAX).size_hint(), (1, Some(1))); + assert_eq!( + super::range(usize::MAX - 1, usize::MAX).size_hint(), + (1, Some(1)) + ); assert_eq!(super::range(-10, -1).size_hint(), (9, Some(9))); - assert_eq!(super::range(isize::MIN, isize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!( + super::range(isize::MIN, isize::MAX).size_hint(), + (usize::MAX, Some(usize::MAX)) + ); } #[test] @@ -366,39 +401,58 @@ mod tests { fn test_range_128() { use core::{i128, u128}; - assert!(super::range(0i128, 5) - .eq([0, 1, 2, 3, 4].iter().cloned())); - assert!(super::range(-10i128, -1) - .eq([-10, -9, -8, -7, -6, -5, -4, -3, -2].iter().cloned())); - assert!(super::range(0u128, 5).rev() - .eq([4, 3, 2, 1, 0].iter().cloned())); + assert!(super::range(0i128, 5).eq([0, 1, 2, 3, 4].iter().cloned())); + assert!(super::range(-10i128, -1).eq([-10, -9, -8, -7, -6, -5, -4, -3, -2].iter().cloned())); + assert!(super::range(0u128, 5) + .rev() + .eq([4, 3, 2, 1, 0].iter().cloned())); - assert_eq!(super::range(i128::MIN, i128::MIN+1).size_hint(), (1, Some(1))); - assert_eq!(super::range(i128::MAX - 1, i128::MAX).size_hint(), (1, Some(1))); - assert_eq!(super::range(i128::MIN, i128::MAX).size_hint(), (usize::MAX, None)); + assert_eq!( + super::range(i128::MIN, i128::MIN + 1).size_hint(), + (1, Some(1)) + ); + assert_eq!( + super::range(i128::MAX - 1, i128::MAX).size_hint(), + (1, Some(1)) + ); + assert_eq!( + super::range(i128::MIN, i128::MAX).size_hint(), + (usize::MAX, None) + ); - assert_eq!(super::range(u128::MAX - 1, u128::MAX).size_hint(), (1, Some(1))); - assert_eq!(super::range(0, usize::MAX as u128).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!(super::range(0, usize::MAX as u128 + 1).size_hint(), (usize::MAX, None)); + assert_eq!( + super::range(u128::MAX - 1, u128::MAX).size_hint(), + (1, Some(1)) + ); + assert_eq!( + super::range(0, usize::MAX as u128).size_hint(), + (usize::MAX, Some(usize::MAX)) + ); + assert_eq!( + super::range(0, usize::MAX as u128 + 1).size_hint(), + (usize::MAX, None) + ); assert_eq!(super::range(0, i128::MAX).size_hint(), (usize::MAX, None)); } #[test] fn test_range_inclusive() { + assert!(super::range_inclusive(0, 5).eq([0, 1, 2, 3, 4, 5].iter().cloned())); assert!(super::range_inclusive(0, 5) - .eq([0, 1, 2, 3, 4, 5].iter().cloned())); - assert!(super::range_inclusive(0, 5).rev() - .eq([5, 4, 3, 2, 1, 0].iter().cloned())); + .rev() + .eq([5, 4, 3, 2, 1, 0].iter().cloned())); assert_eq!(super::range_inclusive(200, -5).count(), 0); assert_eq!(super::range_inclusive(200, -5).rev().count(), 0); - assert!(super::range_inclusive(200, 200) - .eq(iter::once(200))); - assert!(super::range_inclusive(200, 200).rev() - .eq(iter::once(200))); - assert_eq!(super::range_inclusive(isize::MIN, isize::MAX - 1).size_hint(), - (usize::MAX, Some(usize::MAX))); - assert_eq!(super::range_inclusive(isize::MIN, isize::MAX).size_hint(), - (usize::MAX, None)); + assert!(super::range_inclusive(200, 200).eq(iter::once(200))); + assert!(super::range_inclusive(200, 200).rev().eq(iter::once(200))); + assert_eq!( + super::range_inclusive(isize::MIN, isize::MAX - 1).size_hint(), + (usize::MAX, Some(usize::MAX)) + ); + assert_eq!( + super::range_inclusive(isize::MIN, isize::MAX).size_hint(), + (usize::MAX, None) + ); } #[test] @@ -406,40 +460,42 @@ mod tests { fn test_range_inclusive_128() { use core::i128; + assert!(super::range_inclusive(0u128, 5).eq([0, 1, 2, 3, 4, 5].iter().cloned())); assert!(super::range_inclusive(0u128, 5) - .eq([0, 1, 2, 3, 4, 5].iter().cloned())); - assert!(super::range_inclusive(0u128, 5).rev() - .eq([5, 4, 3, 2, 1, 0].iter().cloned())); + .rev() + .eq([5, 4, 3, 2, 1, 0].iter().cloned())); assert_eq!(super::range_inclusive(200i128, -5).count(), 0); assert_eq!(super::range_inclusive(200i128, -5).rev().count(), 0); + assert!(super::range_inclusive(200u128, 200).eq(iter::once(200))); assert!(super::range_inclusive(200u128, 200) - .eq(iter::once(200))); - assert!(super::range_inclusive(200u128, 200).rev() - .eq(iter::once(200))); - assert_eq!(super::range_inclusive(isize::MIN as i128, isize::MAX as i128 - 1).size_hint(), - (usize::MAX, Some(usize::MAX))); - assert_eq!(super::range_inclusive(isize::MIN as i128, isize::MAX as i128).size_hint(), - (usize::MAX, None)); - assert_eq!(super::range_inclusive(isize::MIN as i128, isize::MAX as i128 + 1).size_hint(), - (usize::MAX, None)); - assert_eq!(super::range_inclusive(i128::MIN, i128::MAX).size_hint(), - (usize::MAX, None)); + .rev() + .eq(iter::once(200))); + assert_eq!( + super::range_inclusive(isize::MIN as i128, isize::MAX as i128 - 1).size_hint(), + (usize::MAX, Some(usize::MAX)) + ); + assert_eq!( + super::range_inclusive(isize::MIN as i128, isize::MAX as i128).size_hint(), + (usize::MAX, None) + ); + assert_eq!( + super::range_inclusive(isize::MIN as i128, isize::MAX as i128 + 1).size_hint(), + (usize::MAX, None) + ); + assert_eq!( + super::range_inclusive(i128::MIN, i128::MAX).size_hint(), + (usize::MAX, None) + ); } #[test] fn test_range_step() { - assert!(super::range_step(0, 20, 5) - .eq([0, 5, 10, 15].iter().cloned())); - assert!(super::range_step(20, 0, -5) - .eq([20, 15, 10, 5].iter().cloned())); - assert!(super::range_step(20, 0, -6) - .eq([20, 14, 8, 2].iter().cloned())); - assert!(super::range_step(200u8, 255, 50) - .eq([200u8, 250].iter().cloned())); - assert!(super::range_step(200, -5, 1) - .eq(iter::empty())); - assert!(super::range_step(200, 200, 1) - .eq(iter::empty())); + assert!(super::range_step(0, 20, 5).eq([0, 5, 10, 15].iter().cloned())); + assert!(super::range_step(20, 0, -5).eq([20, 15, 10, 5].iter().cloned())); + assert!(super::range_step(20, 0, -6).eq([20, 14, 8, 2].iter().cloned())); + assert!(super::range_step(200u8, 255, 50).eq([200u8, 250].iter().cloned())); + assert!(super::range_step(200, -5, 1).eq(iter::empty())); + assert!(super::range_step(200, 200, 1).eq(iter::empty())); } #[test] @@ -447,34 +503,22 @@ mod tests { fn test_range_step_128() { use core::u128::MAX as UMAX; - assert!(super::range_step(0u128, 20, 5) - .eq([0, 5, 10, 15].iter().cloned())); - assert!(super::range_step(20i128, 0, -5) - .eq([20, 15, 10, 5].iter().cloned())); - assert!(super::range_step(20i128, 0, -6) - .eq([20, 14, 8, 2].iter().cloned())); - assert!(super::range_step(UMAX - 55, UMAX, 50) - .eq([UMAX - 55, UMAX - 5].iter().cloned())); - assert!(super::range_step(200i128, -5, 1) - .eq(iter::empty())); - assert!(super::range_step(200i128, 200, 1) - .eq(iter::empty())); + assert!(super::range_step(0u128, 20, 5).eq([0, 5, 10, 15].iter().cloned())); + assert!(super::range_step(20i128, 0, -5).eq([20, 15, 10, 5].iter().cloned())); + assert!(super::range_step(20i128, 0, -6).eq([20, 14, 8, 2].iter().cloned())); + assert!(super::range_step(UMAX - 55, UMAX, 50).eq([UMAX - 55, UMAX - 5].iter().cloned())); + assert!(super::range_step(200i128, -5, 1).eq(iter::empty())); + assert!(super::range_step(200i128, 200, 1).eq(iter::empty())); } #[test] fn test_range_step_inclusive() { - assert!(super::range_step_inclusive(0, 20, 5) - .eq([0, 5, 10, 15, 20].iter().cloned())); - assert!(super::range_step_inclusive(20, 0, -5) - .eq([20, 15, 10, 5, 0].iter().cloned())); - assert!(super::range_step_inclusive(20, 0, -6) - .eq([20, 14, 8, 2].iter().cloned())); - assert!(super::range_step_inclusive(200u8, 255, 50) - .eq([200u8, 250].iter().cloned())); - assert!(super::range_step_inclusive(200, -5, 1) - .eq(iter::empty())); - assert!(super::range_step_inclusive(200, 200, 1) - .eq(iter::once(200))); + assert!(super::range_step_inclusive(0, 20, 5).eq([0, 5, 10, 15, 20].iter().cloned())); + assert!(super::range_step_inclusive(20, 0, -5).eq([20, 15, 10, 5, 0].iter().cloned())); + assert!(super::range_step_inclusive(20, 0, -6).eq([20, 14, 8, 2].iter().cloned())); + assert!(super::range_step_inclusive(200u8, 255, 50).eq([200u8, 250].iter().cloned())); + assert!(super::range_step_inclusive(200, -5, 1).eq(iter::empty())); + assert!(super::range_step_inclusive(200, 200, 1).eq(iter::once(200))); } #[test] @@ -482,17 +526,12 @@ mod tests { fn test_range_step_inclusive_128() { use core::u128::MAX as UMAX; - assert!(super::range_step_inclusive(0u128, 20, 5) - .eq([0, 5, 10, 15, 20].iter().cloned())); - assert!(super::range_step_inclusive(20i128, 0, -5) - .eq([20, 15, 10, 5, 0].iter().cloned())); - assert!(super::range_step_inclusive(20i128, 0, -6) - .eq([20, 14, 8, 2].iter().cloned())); + assert!(super::range_step_inclusive(0u128, 20, 5).eq([0, 5, 10, 15, 20].iter().cloned())); + assert!(super::range_step_inclusive(20i128, 0, -5).eq([20, 15, 10, 5, 0].iter().cloned())); + assert!(super::range_step_inclusive(20i128, 0, -6).eq([20, 14, 8, 2].iter().cloned())); assert!(super::range_step_inclusive(UMAX - 55, UMAX, 50) - .eq([UMAX - 55, UMAX - 5].iter().cloned())); - assert!(super::range_step_inclusive(200i128, -5, 1) - .eq(iter::empty())); - assert!(super::range_step_inclusive(200i128, 200, 1) - .eq(iter::once(200))); + .eq([UMAX - 55, UMAX - 5].iter().cloned())); + assert!(super::range_step_inclusive(200i128, -5, 1).eq(iter::empty())); + assert!(super::range_step_inclusive(200i128, 200, 1).eq(iter::once(200))); } } diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml index 55f7eb0fdd0d..9923a396d0ce 100644 --- a/toolkit/library/rust/shared/Cargo.toml +++ b/toolkit/library/rust/shared/Cargo.toml @@ -9,7 +9,7 @@ description = "Shared Rust code for libxul" geckoservo = { path = "../../../../servo/ports/geckolib" } kvstore = { path = "../../../components/kvstore" } lmdb-rkv-sys = { version = "0.11", features = ["mdb_idl_logn_9"] } -mp4parse_capi = { git = "https://github.com/mozilla/mp4parse-rust", rev = "63325444ae3388599f2f222775eebdde4c2f9f30" } +mp4parse_capi = { git = "https://github.com/mozilla/mp4parse-rust", rev = "d5a37fd0bd51e06a53274c68213b00136aba83a6" } nserror = { path = "../../../../xpcom/rust/nserror" } nsstring = { path = "../../../../xpcom/rust/nsstring" } netwerk_helper = { path = "../../../../netwerk/base/rust-helper" }