diff --git a/src/algorithm/dyadic/mod.rs b/src/algorithm/dyadic/mod.rs index 8c624a15..96bfca73 100644 --- a/src/algorithm/dyadic/mod.rs +++ b/src/algorithm/dyadic/mod.rs @@ -462,33 +462,28 @@ impl Value { impl Value { /// Use this value as counts to `keep` another pub fn keep(self, kept: Self, env: &Uiua) -> UiuaResult { - self.into_nums_with( + let counts = self.as_nums( env, "Keep amount must be a positive real number \ or list of natural numbers", - false, - |counts, shape| { - Ok(if shape.len() == 0 { - match kept { - Value::Num(a) => a.keep_scalar_real(counts[0], env)?.into(), - Value::Byte(a) => { - a.convert::().keep_scalar_real(counts[0], env)?.into() - } - Value::Complex(a) => a.keep_scalar_real(counts[0], env)?.into(), - Value::Char(a) => a.keep_scalar_real(counts[0], env)?.into(), - Value::Box(a) => a.keep_scalar_real(counts[0], env)?.into(), - } - } else { - match kept { - Value::Num(a) => a.keep_list(counts, env)?.into(), - Value::Byte(a) => a.keep_list(counts, env)?.into(), - Value::Complex(a) => a.keep_list(counts, env)?.into(), - Value::Char(a) => a.keep_list(counts, env)?.into(), - Value::Box(a) => a.keep_list(counts, env)?.into(), - } - }) - }, - ) + )?; + Ok(if self.rank() == 0 { + match kept { + Value::Num(a) => a.keep_scalar_real(counts[0], env)?.into(), + Value::Byte(a) => a.convert::().keep_scalar_real(counts[0], env)?.into(), + Value::Complex(a) => a.keep_scalar_real(counts[0], env)?.into(), + Value::Char(a) => a.keep_scalar_real(counts[0], env)?.into(), + Value::Box(a) => a.keep_scalar_real(counts[0], env)?.into(), + } + } else { + match kept { + Value::Num(a) => a.keep_list(&counts, env)?.into(), + Value::Byte(a) => a.keep_list(&counts, env)?.into(), + Value::Complex(a) => a.keep_list(&counts, env)?.into(), + Value::Char(a) => a.keep_list(&counts, env)?.into(), + Value::Box(a) => a.keep_list(&counts, env)?.into(), + } + }) } pub(crate) fn unkeep(self, env: &Uiua) -> UiuaResult<(Self, Self)> { self.generic_into( @@ -500,26 +495,22 @@ impl Value { ) } pub(crate) fn undo_keep(self, kept: Self, into: Self, env: &Uiua) -> UiuaResult { - self.into_nums_with_other( - kept, + let counts = self.as_nums( env, - "Keep amount must be a natural number \ + "Keep amount must be a positive real number \ or list of natural numbers", - false, - |counts, shape, kept| { - if shape.len() == 0 { - return Err(env.error("Cannot invert scalar keep")); - } - kept.generic_bin_into( - into, - |a, b| a.undo_keep(counts, b, env).map(Into::into), - |a, b| a.undo_keep(counts, b, env).map(Into::into), - |a, b| a.undo_keep(counts, b, env).map(Into::into), - |a, b| a.undo_keep(counts, b, env).map(Into::into), - |a, b| a.undo_keep(counts, b, env).map(Into::into), - |a, b| env.error(format!("Cannot unkeep {a} array with {b} array")), - ) - }, + )?; + if self.rank() == 0 { + return Err(env.error("Cannot invert scalar keep")); + } + kept.generic_bin_into( + into, + |a, b| a.undo_keep(&counts, b, env).map(Into::into), + |a, b| a.undo_keep(&counts, b, env).map(Into::into), + |a, b| a.undo_keep(&counts, b, env).map(Into::into), + |a, b| a.undo_keep(&counts, b, env).map(Into::into), + |a, b| a.undo_keep(&counts, b, env).map(Into::into), + |a, b| env.error(format!("Cannot unkeep {a} array with {b} array")), ) } } diff --git a/src/algorithm/dyadic/structure.rs b/src/algorithm/dyadic/structure.rs index 50caf8ee..09ed5ed8 100644 --- a/src/algorithm/dyadic/structure.rs +++ b/src/algorithm/dyadic/structure.rs @@ -79,24 +79,18 @@ impl Value { } /// Use this array as an index to pick from another pub fn pick(self, from: Self, env: &Uiua) -> UiuaResult { - self.into_ints_with( - env, - "Index must be an array of integers", - true, - |index_data, index_shape| { - Ok(match from { - Value::Num(a) => Value::Num(a.pick(index_shape, index_data, env)?), - Value::Byte(a) => op_bytes_retry_fill( - a, - |a| a.pick(index_shape, index_data, env).map(Into::into), - |a| a.pick(index_shape, index_data, env).map(Into::into), - )?, - Value::Complex(a) => Value::Complex(a.pick(index_shape, index_data, env)?), - Value::Char(a) => Value::Char(a.pick(index_shape, index_data, env)?), - Value::Box(a) => Value::Box(a.pick(index_shape, index_data, env)?), - }) - }, - ) + let (index_shape, index_data) = self.as_shaped_indices(env)?; + Ok(match from { + Value::Num(a) => Value::Num(a.pick(index_shape, &index_data, env)?), + Value::Byte(a) => op_bytes_retry_fill( + a, + |a| a.pick(index_shape, &index_data, env).map(Into::into), + |a| a.pick(index_shape, &index_data, env).map(Into::into), + )?, + Value::Complex(a) => Value::Complex(a.pick(index_shape, &index_data, env)?), + Value::Char(a) => Value::Char(a.pick(index_shape, &index_data, env)?), + Value::Box(a) => Value::Box(a.pick(index_shape, &index_data, env)?), + }) } pub(crate) fn undo_pick(self, index: Self, into: Self, env: &Uiua) -> UiuaResult { let (idx_shape, index_data) = index.as_shaped_indices(env)?; @@ -787,24 +781,18 @@ impl Array { impl Value { /// Use this value to `select` from another pub fn select(self, from: &Self, env: &Uiua) -> UiuaResult { - self.into_ints_with( - env, - "Index must be an array of integers", - true, - |indices_data, indices_shape| { - Ok(match from { - Value::Num(a) => a.select(indices_shape, indices_data, env)?.into(), - Value::Byte(a) => op_bytes_ref_retry_fill( - a, - |a| Ok(a.select(indices_shape, indices_data, env)?.into()), - |a| Ok(a.select(indices_shape, indices_data, env)?.into()), - )?, - Value::Complex(a) => a.select(indices_shape, indices_data, env)?.into(), - Value::Char(a) => a.select(indices_shape, indices_data, env)?.into(), - Value::Box(a) => a.select(indices_shape, indices_data, env)?.into(), - }) - }, - ) + let (indices_shape, indices_data) = self.as_shaped_indices(env)?; + Ok(match from { + Value::Num(a) => a.select(indices_shape, &indices_data, env)?.into(), + Value::Byte(a) => op_bytes_ref_retry_fill( + a, + |a| Ok(a.select(indices_shape, &indices_data, env)?.into()), + |a| Ok(a.select(indices_shape, &indices_data, env)?.into()), + )?, + Value::Complex(a) => a.select(indices_shape, &indices_data, env)?.into(), + Value::Char(a) => a.select(indices_shape, &indices_data, env)?.into(), + Value::Box(a) => a.select(indices_shape, &indices_data, env)?.into(), + }) } pub(crate) fn undo_select(self, index: Self, into: Self, env: &Uiua) -> UiuaResult { let (idx_shape, ind) = index.as_shaped_indices(env)?; diff --git a/src/value.rs b/src/value.rs index 2b93b9b8..f60e54ab 100644 --- a/src/value.rs +++ b/src/value.rs @@ -667,22 +667,6 @@ impl Value { ) -> Result, C::Error> { self.as_number_list(ctx, requirement, |f| f.fract() == 0.0, |f| f as isize) } - pub(crate) fn into_ints_with( - self, - ctx: &C, - requirement: &'static str, - allow_non_list: bool, - with: impl FnOnce(&[isize], &Shape) -> Result + Clone, - ) -> Result { - self.into_number_list_with( - ctx, - requirement, - allow_non_list, - |f| f.fract() == 0.0, - |f| f as isize, - with, - ) - } pub(crate) fn as_ints_or_infs( &self, env: &Uiua, @@ -874,33 +858,6 @@ impl Value { pub fn as_nums(&self, env: &Uiua, requirement: &'static str) -> UiuaResult> { self.as_number_list(env, requirement, |_| true, |f| f) } - pub(crate) fn into_nums_with( - self, - ctx: &C, - requirement: &'static str, - allow_non_list: bool, - with: impl FnOnce(&[f64], &Shape) -> Result + Clone, - ) -> Result { - self.into_number_list_with(ctx, requirement, allow_non_list, |_| true, |f| f, with) - } - pub(crate) fn into_nums_with_other( - self, - other: Self, - ctx: &C, - requirement: &'static str, - allow_non_list: bool, - with: impl FnOnce(&[f64], &Shape, Value) -> Result + Clone, - ) -> Result { - self.into_number_list_with_other( - other, - ctx, - requirement, - allow_non_list, - |_| true, - |f| f, - with, - ) - } /// Attempt to convert the array to a list of natural numbers /// /// The `requirement` parameter is used in error messages. @@ -916,42 +873,6 @@ impl Value { |f| f as usize, ) } - #[allow(dead_code)] - pub(crate) fn into_nats_with( - self, - ctx: &C, - requirement: &'static str, - allow_non_list: bool, - with: impl FnOnce(&[usize], &Shape) -> Result + Clone, - ) -> Result { - self.into_number_list_with( - ctx, - requirement, - allow_non_list, - |f| f.fract() == 0.0 && f >= 0.0, - |f| f as usize, - with, - ) - } - #[allow(dead_code)] - pub(crate) fn into_nats_with_other( - self, - other: Self, - ctx: &C, - requirement: &'static str, - allow_non_list: bool, - with: impl FnOnce(&[usize], &Shape, Value) -> Result + Clone, - ) -> Result { - self.into_number_list_with_other( - other, - ctx, - requirement, - allow_non_list, - |f| f.fract() == 0.0 && f >= 0.0, - |f| f as usize, - with, - ) - } /// Attempt to convert the array to a list of bytes /// /// The `requirement` parameter is used in error messages. @@ -1045,145 +966,6 @@ impl Value { } }) } - pub(crate) fn into_number_list_with( - self, - ctx: &C, - requirement: &'static str, - allow_non_list: bool, - test: fn(f64) -> bool, - convert: fn(f64) -> N, - with: impl FnOnce(&[N], &Shape) -> Result + Clone, - ) -> Result - where - C: ErrorContext, - { - match self { - Value::Num(nums) => { - if nums.rank() > 1 && !allow_non_list { - return Err( - ctx.error(format!("{requirement}, but its rank is {}", nums.rank())) - ); - } - let mut result = Vec::with_capacity(nums.row_count()); - for &num in &nums.data { - if !test(num) { - return Err(ctx.error(requirement)); - } - result.push(convert(num)); - } - with(&result, &nums.shape) - } - Value::Byte(bytes) => { - if bytes.rank() > 1 && !allow_non_list { - return Err( - ctx.error(format!("{requirement}, but its rank is {}", bytes.rank())) - ); - } - let mut result = Vec::with_capacity(bytes.row_count()); - for &byte in &bytes.data { - let num = byte as f64; - if !test(num) { - return Err(ctx.error(requirement)); - } - result.push(convert(num)); - } - with(&result, &bytes.shape) - } - Value::Box(mut arr) => { - for Boxed(b) in &mut arr.data { - *b = take(b).into_number_list_with( - ctx, - requirement, - allow_non_list, - test, - convert, - with.clone(), - )?; - } - Ok(Value::Box(arr)) - } - value => Err(ctx.error(format!( - "{requirement}, but it is {}", - value.type_name_plural() - ))), - } - } - #[allow(clippy::too_many_arguments)] - pub(crate) fn into_number_list_with_other( - self, - other: Self, - ctx: &C, - requirement: &'static str, - allow_non_list: bool, - test: fn(f64) -> bool, - convert: fn(f64) -> N, - with: impl FnOnce(&[N], &Shape, Value) -> Result + Clone, - ) -> Result - where - C: ErrorContext, - { - match self { - Value::Num(nums) => { - if nums.rank() > 1 && !allow_non_list { - return Err( - ctx.error(format!("{requirement}, but its rank is {}", nums.rank())) - ); - } - let mut result = Vec::with_capacity(nums.row_count()); - for &num in &nums.data { - if !test(num) { - return Err(ctx.error(requirement)); - } - result.push(convert(num)); - } - with(&result, &nums.shape, other) - } - Value::Byte(bytes) => { - if bytes.rank() > 1 && !allow_non_list { - return Err( - ctx.error(format!("{requirement}, but its rank is {}", bytes.rank())) - ); - } - let mut result = Vec::with_capacity(bytes.row_count()); - for &byte in &bytes.data { - let num = byte as f64; - if !test(num) { - return Err(ctx.error(requirement)); - } - result.push(convert(num)); - } - with(&result, &bytes.shape, other) - } - Value::Box(mut arr) => { - if !arr.shape.starts_with(other.shape()) { - return Err(ctx.error(format!( - "Shapes {} and {} are not compatible", - arr.shape, - other.shape() - ))); - } - let other_row_shape = Shape::from(&arr.shape[other.rank()..]); - for (Boxed(bx), other) in (arr.data.as_mut_slice().iter_mut()) - .zip(other.into_row_shaped_slices(other_row_shape.clone())) - { - *bx = take(bx).into_number_list_with_other( - other.unboxed(), - ctx, - requirement, - allow_non_list, - test, - convert, - with.clone(), - )?; - } - Ok(Value::Box(arr)) - } - value => Err(ctx.error(format!( - "{requirement}, but it is {}", - value.type_name_plural() - ))), - } - } pub(crate) fn as_integer_array( &self, env: &Uiua,