Bug 1660551 - Update mp4parse-rust to d5a37fd. r=kinetik

Differential Revision: https://phabricator.services.mozilla.com/D87931
This commit is contained in:
Jon Bauman 2020-08-25 17:54:45 +00:00
Родитель 94c26b235a
Коммит 14a9a05444
32 изменённых файлов: 1303 добавлений и 670 удалений

Просмотреть файл

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

14
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",
]

Просмотреть файл

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

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

2
third_party/rust/mp4parse/src/fallible.rs поставляемый
Просмотреть файл

@ -256,7 +256,7 @@ impl<T> TryVec<T> {
Ok(())
}
fn reserve(&mut self, additional: usize) -> Result<()> {
pub fn reserve(&mut self, additional: usize) -> Result<()> {
#[cfg(feature = "mp4parse_fallible")]
{
let available = self

59
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<T: Num>(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<T: Num>(pub T, pub usize);
pub struct TrackScaledTime<T>(pub T, pub usize);
impl<T> std::ops::Add for TrackScaledTime<T>
where
T: Num,
T: num_traits::CheckedAdd,
{
type Output = TrackScaledTime<T>;
type Output = Option<Self>;
fn add(self, other: TrackScaledTime<T>) -> TrackScaledTime<T> {
TrackScaledTime::<T>(self.0 + other.0, self.1)
fn add(self, other: TrackScaledTime<T>) -> Self::Output {
self.0.checked_add(&other.0).map(|sum| Self(sum, self.1))
}
}
@ -1953,6 +1953,7 @@ fn read_stbl<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
}
/// Parse an ftyp box.
/// See ISO 14496-12:2015 § 4.3
fn read_ftyp<T: Read>(src: &mut BMFFBox<T>) -> Result<FileTypeBox> {
let major = be_u32(src)?;
let minor = be_u32(src)?;
@ -1962,7 +1963,7 @@ fn read_ftyp<T: Read>(src: &mut BMFFBox<T>) -> Result<FileTypeBox> {
}
// 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<T: Read>(src: &mut BMFFBox<T>) -> Result<TrackHeaderBox> {
}
/// Parse a elst box.
/// See ISO 14496-12:2015 § 8.6.6
fn read_elst<T: Read>(src: &mut BMFFBox<T>) -> Result<EditListBox> {
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<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaHeaderBox> {
}
/// Parse a stco box.
/// See ISO 14496-12:2015 § 8.7.5
fn read_stco<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
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<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
}
/// Parse a co64 box.
/// See ISO 14496-12:2015 § 8.7.5
fn read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
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<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
}
/// Parse a stss box.
/// See ISO 14496-12:2015 § 8.6.2
fn read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
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<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
}
/// Parse a stsc box.
/// See ISO 14496-12:2015 § 8.7.4
fn read_stsc<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox> {
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<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox> {
Ok(SampleToChunkBox { samples })
}
/// Parse a Composition Time to Sample Box
/// See ISO 14496-12:2015 § 8.6.1.3
fn read_ctts<T: Read>(src: &mut BMFFBox<T>) -> Result<CompositionOffsetBox> {
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<T: Read>(src: &mut BMFFBox<T>) -> Result<CompositionOffsetBox> {
}
/// Parse a stsz box.
/// See ISO 14496-12:2015 § 8.7.3.2
fn read_stsz<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox> {
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<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox> {
}
/// Parse a stts box.
/// See ISO 14496-12:2015 § 8.6.1.2
fn read_stts<T: Read>(src: &mut BMFFBox<T>) -> Result<TimeToSampleBox> {
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<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
let (_, _) = read_fullbox_extra(src)?;
@ -2709,6 +2730,7 @@ fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
}
/// Parse `FLACSpecificBox`.
/// See https://github.com/xiph/flac/blob/master/doc/isoflac.txt § 3.3.2
fn read_dfla<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACSpecificBox> {
let (version, flags) = read_fullbox_extra(src)?;
if version != 0 {
@ -3135,6 +3157,7 @@ fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleEntry>
/// Parse a stsd box.
/// See ISO 14496-12:2015 § 8.5.2
/// See ISO 14496-14:2010 § 6.7.2
fn read_stsd<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleDescriptionBox> {
let (_, _) = read_fullbox_extra(src)?;

Просмотреть файл

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

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

Просмотреть файл

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

259
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<T>(pub T);
impl<T> From<T> for CheckedInteger<T> {
fn from(i: T) -> Self {
Self(i)
}
}
// Orphan rules prevent a more general implementation, but this suffices
impl From<CheckedInteger<i64>> for i64 {
fn from(checked: CheckedInteger<i64>) -> i64 {
checked.0
}
}
impl<T, U: Into<T>> Add<U> for CheckedInteger<T>
where
T: CheckedAdd,
{
type Output = Option<Self>;
fn add(self, other: U) -> Self::Output {
self.0.checked_add(&other.into()).map(Into::into)
}
}
impl<T, U: Into<T>> Sub<U> for CheckedInteger<T>
where
T: CheckedSub,
{
type Output = Option<Self>;
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<u64> {
type Output = Option<CheckedInteger<i64>>;
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<T: std::cmp::PartialEq> PartialEq<T> for CheckedInteger<T> {
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
pub media_time: CheckedInteger<i64>, // 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<u64>
}
#[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<u64>,
/// 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<u64>,
/// 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<i64>,
/// 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<i64>,
/// 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<i64>,
/// 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| {
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 as i64,
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,12 +1244,17 @@ 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),
let empty_duration: Option<CheckedInteger<_>> =
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,
};
@ -1148,10 +1262,10 @@ fn get_indice_table(
// '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<i64> {
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<u32> {
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<mp4parse::SampleToChunk>,
stco_offsets: &'a TryVec<u64>,
) -> 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<u32>,
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<u32> 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<u32> {
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<TryVec<Mp4parseIndice>> {
#[allow(clippy::reversed_empty_ranges)]
fn create_sample_table(
track: &Track,
track_offset_time: CheckedInteger<i64>,
) -> Option<TryVec<Mp4parseIndice>> {
let timescale = match track.timescale {
Some(ref t) => TrackTimeScale::<i64>(t.0 as i64, t.1),
_ => return None,
@ -1341,31 +1482,32 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<TryVec<M
_ => 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<TryVec<M
.push(Mp4parseIndice {
start_offset,
end_offset,
start_composition: 0,
end_composition: 0,
start_decode: 0,
sync: !has_sync_table,
..Default::default()
})
.ok()?;
}
@ -1389,7 +1529,7 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<TryVec<M
if let Some(ref v) = track.stss {
for iter in &v.samples {
match iter
.checked_sub(1)
.checked_sub(&1)
.and_then(|idx| sample_table.get_mut(idx as usize))
{
Some(elem) => elem.sync = true,
@ -1426,25 +1566,20 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<TryVec<M
let mut sum_delta = TrackScaledTime::<i64>(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<TryVec<M
// calculate to correct the composition end time.
if !sample_table.is_empty() {
// Create an index table refers to sample_table and sorted by start_composisiton time.
let mut sort_table = TryVec::new();
let mut sort_table = TryVec::with_capacity(sample_table.len()).ok()?;
for i in 0..sample_table.len() {
sort_table.push(i).ok()?;
}
sort_table.sort_by_key(|i| match sample_table.get(*i) {
Some(v) => 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::<byteorder::NativeEndian>(content_len as u32)
.write_u32::<byteorder::NativeEndian>(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)

Просмотреть файл

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

Просмотреть файл

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

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

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

176
third_party/rust/num-integer/benches/gcd.rs поставляемый Normal file
Просмотреть файл

@ -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<Item = u128> {
(0..185).scan((0, 1), |&mut (ref mut a, ref mut b), _| {
let tmp = *a;
*a = *b;
*b += tmp;
Some(*b)
})
}
fn run_bench<T: Integer + Bounded + Copy + 'static>(b: &mut Bencher, gcd: fn(&T, &T) -> T)
where
T: AsPrimitive<u128>,
u128: AsPrimitive<T>,
{
let max_value: u128 = T::max_value().as_();
let pairs: Vec<(T, T)> = fibonacci()
.collect::<Vec<_>>()
.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);

Просмотреть файл

@ -13,11 +13,7 @@ use test::{black_box, Bencher};
trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
impl<T> BenchInteger for T
where
T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static,
{
}
impl<T> BenchInteger for T where T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
fn bench<T, F>(b: &mut Bencher, v: &[T], f: F, n: u32)
where

3
third_party/rust/num-integer/bors.toml поставляемый
Просмотреть файл

@ -1,3 +0,0 @@
status = [
"continuous-integration/travis-ci/push",
]

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

12
third_party/rust/num-integer/ci/rustup.sh поставляемый
Просмотреть файл

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

23
third_party/rust/num-integer/ci/test_full.sh поставляемый
Просмотреть файл

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

497
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: Copy + Integer + NumAssign>(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<Self>
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>, 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<A> {
pub gcd: A,
pub x: A,
pub y: A,
_hidden: (),
}
/// Simultaneous integer division and modulus
@ -194,6 +376,11 @@ pub fn mod_floor<T: Integer>(x: T, y: T) -> T {
pub fn div_mod_floor<T: Integer>(x: T, y: T) -> (T, T) {
x.div_mod_floor(&y)
}
/// Ceiled integer division
#[inline]
pub fn div_ceil<T: Integer>(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<T: Integer>(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<T: Integer>(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) }
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>, 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(( 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), (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(( 1, 2), ( 0, 1));
test_nd_dm(( 1, -2), (-1, -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_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: Copy + Debug + Integer + NumAssign>(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) }
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>, 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<T> {
}
impl<T> IterBinomial<T>
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<T> IterBinomial<T>
/// For larger n, `T` should be a bigint type.
pub fn new(n: T) -> IterBinomial<T> {
IterBinomial {
k: T::zero(), a: T::one(), n: n
k: T::zero(),
a: T::one(),
n: n,
}
}
}
impl<T> Iterator for IterBinomial<T>
where T: Integer + Clone
where
T: Integer + Clone,
{
type Item = T;
@ -732,7 +1062,7 @@ impl<T> Iterator for IterBinomial<T>
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<T> Iterator for IterBinomial<T>
fn multiply_and_divide<T: Integer + Clone>(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<T: Integer + Clone>(mut n: T, k: T) -> T {
/// Calculate the multinomial coefficient.
pub fn multinomial<T: Integer + Clone>(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<T: Integer + Clone>(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(),
assert!(
o.is_none(),
"sanity checking that {} input {} * {} overflows",
stringify!($t), x, y);
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);

75
third_party/rust/num-integer/src/roots.rs поставляемый
Просмотреть файл

@ -202,37 +202,39 @@ fn log2<T: PrimInt>(x: T) -> u32 {
macro_rules! unsigned_roots {
($T:ident) => {
impl Roots for $T {
#[inline]
fn nth_root(&self, n: u32) -> Self {
fn go(a: $T, n: u32) -> $T {
// 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(),
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;
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
return if a <= core::u64::MAX as $T {
(a as u64).nth_root(n) as $T
} else {
let lo = (self >> n).nth_root(n) << 1;
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 <= *self => hi,
Some(x) if x <= a => hi,
_ => lo,
}
} else {
if hi.pow(n) <= *self {
if hi.pow(n) <= a {
hi
} else {
lo
@ -262,24 +264,27 @@ macro_rules! unsigned_roots {
let n1 = n - 1;
let next = |x: $T| {
let y = match checked_pow(x, n1 as usize) {
Some(ax) => self / ax,
Some(ax) => a / ax,
None => 0,
};
(y + x * n1 as $T) / n as $T
};
fixpoint(guess(*self, n), next)
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.
// 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
return if a <= core::u64::MAX as $T {
(a as u64).sqrt() as $T
} else {
let lo = (self >> 2u32).sqrt() << 1;
let lo = (a >> 2u32).sqrt() << 1;
let hi = lo + 1;
if hi * hi <= *self {
if hi * hi <= a {
hi
} else {
lo
@ -287,8 +292,8 @@ macro_rules! unsigned_roots {
};
}
if *self < 4 {
return (*self > 0) as Self;
if a < 4 {
return (a > 0) as $T;
}
#[cfg(feature = "std")]
@ -304,19 +309,23 @@ macro_rules! unsigned_roots {
}
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
let next = |x: $T| (self / x + x) >> 1;
fixpoint(guess(*self), next)
let next = |x: $T| (a / x + x) >> 1;
fixpoint(guess(a), next)
}
go(*self)
}
#[inline]
fn cbrt(&self) -> Self {
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 *self <= core::u64::MAX as $T {
(*self as u64).cbrt() as $T
return if a <= core::u64::MAX as $T {
(a as u64).cbrt() as $T
} else {
let lo = (self >> 3u32).cbrt() << 1;
let lo = (a >> 3u32).cbrt() << 1;
let hi = lo + 1;
if hi * hi * hi <= *self {
if hi * hi * hi <= a {
hi
} else {
lo
@ -326,7 +335,7 @@ macro_rules! unsigned_roots {
if bits::<$T>() <= 32 {
// Implementation based on Hacker's Delight `icbrt2`
let mut x = *self;
let mut x = a;
let mut y2 = 0;
let mut y = 0;
let smax = bits::<$T>() / 3;
@ -344,11 +353,11 @@ macro_rules! unsigned_roots {
return y;
}
if *self < 8 {
return (*self > 0) as Self;
if a < 8 {
return (a > 0) as $T;
}
if *self <= core::u32::MAX as $T {
return (*self as u32).cbrt() as $T;
if a <= core::u32::MAX as $T {
return (a as u32).cbrt() as $T;
}
#[cfg(feature = "std")]
@ -364,8 +373,10 @@ macro_rules! unsigned_roots {
}
// https://en.wikipedia.org/wiki/Cube_root#Numerical_methods
let next = |x: $T| (self / (x * x) + x * 2) / 3;
fixpoint(guess(*self), next)
let next = |x: $T| (a / (x * x) + x * 2) / 3;
fixpoint(guess(a), next)
}
go(*self)
}
}
};

6
third_party/rust/num-integer/tests/roots.rs поставляемый
Просмотреть файл

@ -10,11 +10,7 @@ use std::mem;
trait TestInteger: Roots + PrimInt + Debug + AsPrimitive<f64> + 'static {}
impl<T> TestInteger for T
where
T: Roots + PrimInt + Debug + AsPrimitive<f64> + 'static,
{
}
impl<T> TestInteger for T where T: Roots + PrimInt + Debug + AsPrimitive<f64> + 'static {}
/// Check that each root is correct
///

Просмотреть файл

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

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

20
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

3
third_party/rust/num-iter/bors.toml поставляемый
Просмотреть файл

@ -1,3 +0,0 @@
status = [
"continuous-integration/travis-ci/push",
]

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

12
third_party/rust/num-iter/ci/rustup.sh поставляемый
Просмотреть файл

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

19
third_party/rust/num-iter/ci/test_full.sh поставляемый
Просмотреть файл

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

271
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<A> {
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<A> {
/// ```
#[inline]
pub fn range<A>(start: A, stop: A) -> Range<A>
where A: Add<A, Output = A> + PartialOrd + Clone + One
where
A: Add<A, Output = A> + 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<T: ToPrimitive>(x: &T) -> Option<u64> {
// FIXME: rust-lang/rust#10414: Unfortunate type bound
impl<A> Iterator for Range<A>
where A: Add<A, Output = A> + PartialOrd + Clone + ToPrimitive
where
A: Add<A, Output = A> + PartialOrd + Clone + ToPrimitive,
{
type Item = A;
@ -113,7 +118,7 @@ impl<A> Iterator for Range<A>
return match b.wrapping_sub(a).to_usize() {
Some(len) => (len, Some(len)),
None => (usize::MAX, None),
}
};
}
}
@ -125,7 +130,8 @@ impl<A> Iterator for Range<A>
/// `Integer` is required to ensure the range will be the same regardless of
/// the direction it is consumed.
impl<A> DoubleEndedIterator for Range<A>
where A: Integer + Clone + ToPrimitive
where
A: Integer + Clone + ToPrimitive,
{
#[inline]
fn next_back(&mut self) -> Option<A> {
@ -148,13 +154,18 @@ pub struct RangeInclusive<A> {
/// Return an iterator over the range [start, stop]
#[inline]
pub fn range_inclusive<A>(start: A, stop: A) -> RangeInclusive<A>
where A: Add<A, Output = A> + PartialOrd + Clone + One
where
A: Add<A, Output = A> + PartialOrd + Clone + One,
{
RangeInclusive{range: range(start, stop), done: false}
RangeInclusive {
range: range(start, stop),
done: false,
}
}
impl<A> Iterator for RangeInclusive<A>
where A: Add<A, Output = A> + PartialOrd + Clone + ToPrimitive
where
A: Add<A, Output = A> + PartialOrd + Clone + ToPrimitive,
{
type Item = A;
@ -182,7 +193,7 @@ impl<A> Iterator for RangeInclusive<A>
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<A> Iterator for RangeInclusive<A>
}
impl<A> DoubleEndedIterator for RangeInclusive<A>
where A: Sub<A, Output = A> + Integer + Clone + ToPrimitive
where
A: Sub<A, Output = A> + Integer + Clone + ToPrimitive,
{
#[inline]
fn next_back(&mut self) -> Option<A> {
@ -219,14 +231,21 @@ pub struct RangeStep<A> {
/// Return an iterator over the range [start, stop) by `step`. It handles overflow by stopping.
#[inline]
pub fn range_step<A>(start: A, stop: A, step: A) -> RangeStep<A>
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<A> Iterator for RangeStep<A>
where A: CheckedAdd + PartialOrd + Clone
where
A: CheckedAdd + PartialOrd + Clone,
{
type Item = A;
@ -236,7 +255,7 @@ impl<A> Iterator for RangeStep<A>
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<A> {
/// Return an iterator over the range [start, stop] by `step`. It handles overflow by stopping.
#[inline]
pub fn range_step_inclusive<A>(start: A, stop: A, step: A) -> RangeStepInclusive<A>
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<A> Iterator for RangeStepInclusive<A>
where A: CheckedAdd + PartialOrd + Clone + PartialEq
where
A: CheckedAdd + PartialOrd + Clone + PartialEq,
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
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<A> Iterator for RangeStepInclusive<A>
#[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<i64> { None }
fn to_u64(&self) -> Option<u64> { None }
fn to_i64(&self) -> Option<i64> {
None
}
fn to_u64(&self) -> Option<u64> {
None
}
}
impl Add<Foo> 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()
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()
.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()
.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)
.rev()
.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));
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)));
assert!(super::range_step_inclusive(200i128, -5, 1).eq(iter::empty()));
assert!(super::range_step_inclusive(200i128, 200, 1).eq(iter::once(200)));
}
}

Просмотреть файл

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