lists.rs (4682B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! Lists have various ways of being animated, this module implements them. 6 //! 7 //! See https://drafts.csswg.org/web-animations-1/#animating-properties 8 9 /// https://drafts.csswg.org/web-animations-1/#by-computed-value 10 pub mod by_computed_value { 11 use crate::values::{ 12 animated::{Animate, Procedure}, 13 distance::{ComputeSquaredDistance, SquaredDistance}, 14 }; 15 use std::iter::FromIterator; 16 17 #[allow(missing_docs)] 18 pub fn animate<T, C>(left: &[T], right: &[T], procedure: Procedure) -> Result<C, ()> 19 where 20 T: Animate, 21 C: FromIterator<T>, 22 { 23 if left.len() != right.len() { 24 return Err(()); 25 } 26 left.iter() 27 .zip(right.iter()) 28 .map(|(left, right)| left.animate(right, procedure)) 29 .collect() 30 } 31 32 #[allow(missing_docs)] 33 pub fn squared_distance<T>(left: &[T], right: &[T]) -> Result<SquaredDistance, ()> 34 where 35 T: ComputeSquaredDistance, 36 { 37 if left.len() != right.len() { 38 return Err(()); 39 } 40 left.iter() 41 .zip(right.iter()) 42 .map(|(left, right)| left.compute_squared_distance(right)) 43 .sum() 44 } 45 } 46 47 /// This is the animation used for some of the types like shadows and filters, where the 48 /// interpolation happens with the zero value if one of the sides is not present. 49 /// 50 /// https://drafts.csswg.org/web-animations-1/#animating-shadow-lists 51 pub mod with_zero { 52 use crate::values::animated::ToAnimatedZero; 53 use crate::values::{ 54 animated::{Animate, Procedure}, 55 distance::{ComputeSquaredDistance, SquaredDistance}, 56 }; 57 use itertools::{EitherOrBoth, Itertools}; 58 use std::iter::FromIterator; 59 60 #[allow(missing_docs)] 61 pub fn animate<T, C>(left: &[T], right: &[T], procedure: Procedure) -> Result<C, ()> 62 where 63 T: Animate + Clone + ToAnimatedZero, 64 C: FromIterator<T>, 65 { 66 if procedure == Procedure::Add { 67 return Ok(left.iter().chain(right.iter()).cloned().collect()); 68 } 69 left.iter() 70 .zip_longest(right.iter()) 71 .map(|it| match it { 72 EitherOrBoth::Both(left, right) => left.animate(right, procedure), 73 EitherOrBoth::Left(left) => left.animate(&left.to_animated_zero()?, procedure), 74 EitherOrBoth::Right(right) => right.to_animated_zero()?.animate(right, procedure), 75 }) 76 .collect() 77 } 78 79 #[allow(missing_docs)] 80 pub fn squared_distance<T>(left: &[T], right: &[T]) -> Result<SquaredDistance, ()> 81 where 82 T: ToAnimatedZero + ComputeSquaredDistance, 83 { 84 left.iter() 85 .zip_longest(right.iter()) 86 .map(|it| match it { 87 EitherOrBoth::Both(left, right) => left.compute_squared_distance(right), 88 EitherOrBoth::Left(item) | EitherOrBoth::Right(item) => { 89 item.to_animated_zero()?.compute_squared_distance(item) 90 }, 91 }) 92 .sum() 93 } 94 } 95 96 /// https://drafts.csswg.org/web-animations-1/#repeatable-list 97 pub mod repeatable_list { 98 use crate::values::{ 99 animated::{Animate, Procedure}, 100 distance::{ComputeSquaredDistance, SquaredDistance}, 101 }; 102 use std::iter::FromIterator; 103 104 #[allow(missing_docs)] 105 pub fn animate<T, C>(left: &[T], right: &[T], procedure: Procedure) -> Result<C, ()> 106 where 107 T: Animate, 108 C: FromIterator<T>, 109 { 110 use num_integer::lcm; 111 // If the length of either list is zero, the least common multiple is undefined. 112 if left.is_empty() || right.is_empty() { 113 return Err(()); 114 } 115 let len = lcm(left.len(), right.len()); 116 left.iter() 117 .cycle() 118 .zip(right.iter().cycle()) 119 .take(len) 120 .map(|(left, right)| left.animate(right, procedure)) 121 .collect() 122 } 123 124 #[allow(missing_docs)] 125 pub fn squared_distance<T>(left: &[T], right: &[T]) -> Result<SquaredDistance, ()> 126 where 127 T: ComputeSquaredDistance, 128 { 129 use num_integer::lcm; 130 if left.is_empty() || right.is_empty() { 131 return Err(()); 132 } 133 let len = lcm(left.len(), right.len()); 134 left.iter() 135 .cycle() 136 .zip(right.iter().cycle()) 137 .take(len) 138 .map(|(left, right)| left.compute_squared_distance(right)) 139 .sum() 140 } 141 }