cargo fmt

This commit is contained in:
Matthieu Baumann
2025-05-23 18:06:00 +02:00
committed by Matthieu Baumann
parent 7b718eae96
commit 16a1e808a2
33 changed files with 169 additions and 117 deletions

View File

@@ -25,13 +25,13 @@ jobs:
- name: "Install wasm-pack"
run: |
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -y
- name: "Install dependencies"
run: |
npm install
- name: "Run cargo clippy"
run: cd src/core && cargo clippy --all-targets --features=webgl2 -- -D warnings
- name: Format check
run: cargo fmt --all -- --check
- name: "Install dependencies"
run: |
npm install
- name: "Build Aladin Lite"
run: |
npm run build:dbg

View File

@@ -1,6 +1,6 @@
[package]
name = "al-api"
version = "3.6.5"
version = "3.7.0"
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
edition = "2018"

View File

@@ -32,5 +32,5 @@ use std::cmp::Eq;
#[wasm_bindgen]
pub enum Formatter {
Sexagesimal,
Decimal
}
Decimal,
}

View File

@@ -1,9 +1,8 @@
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug)]
#[derive(Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct HEALPixCellProjeted {
pub ipix: u64,
pub vx: [f64; 4],
pub vy: [f64; 4],
}
}

View File

@@ -2,27 +2,29 @@
It is used by al-ui and any javascript application calling
the WASM core of aladin lite v3
*/
pub mod angle;
pub mod blend;
pub mod cell;
pub mod color;
pub mod colormap;
pub mod coo_system;
pub mod fov;
pub mod grid;
pub mod hips;
pub mod image;
pub mod moc;
pub mod resources;
pub mod cell;
pub mod fov;
pub mod image;
pub mod angle;
pub trait Abort {
type Item;
fn unwrap_abort(self) -> Self::Item where Self: Sized;
fn unwrap_abort(self) -> Self::Item
where
Self: Sized;
}
impl<T> Abort for Option<T> {
type Item = T;
#[inline]
fn unwrap_abort(self) -> Self::Item {
use std::process;

View File

@@ -1,6 +1,6 @@
[package]
name = "al-core"
version = "3.6.5"
version = "3.7.0"
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
edition = "2018"

View File

@@ -37,7 +37,10 @@ impl ElementArrayBuffer {
usage: u32,
data: B,
) -> ElementArrayBuffer {
let buffer = gl.create_buffer().ok_or("failed to create buffer").unwrap_abort();
let buffer = gl
.create_buffer()
.ok_or("failed to create buffer")
.unwrap_abort();
// Bind the buffer
gl.bind_buffer(
WebGlRenderingCtx::ELEMENT_ARRAY_BUFFER,

View File

@@ -86,7 +86,10 @@ pub fn write(path: PathBuf, entries: HashMap<String, String>) -> Result<(), Box<
for (name, content) in entries {
writeln!(
&mut all_the_files,
r##" out.insert(r"{name}", r#"{content}"#);"##,
r##" out.insert(
r"{name}",
r#"{content}"#,
);"##,
)?;
}

View File

@@ -4,7 +4,6 @@ use crate::tile_fetcher::HiPSLocalFiles;
use crate::math::angle::ToAngle;
use crate::renderable::hips::HiPS;
use crate::{
//async_task::{BuildCatalogIndex, ParseTableTask, TaskExecutor, TaskResult, TaskType},
camera::CameraViewPort,
downloader::Downloader,
healpix::coverage::HEALPixCoverage,
@@ -576,10 +575,10 @@ impl App {
}
// Tiles are fetched if:
let fetch_tiles =
let fetch_tiles =
// * the user is not panning the view
// * or the user is but did not move for at least 100ms
(Time::now() - self.camera.get_time_of_last_move() >= DeltaTime(100.0) || !self.dragging) &&
(Time::now() - self.camera.get_time_of_last_move() >= DeltaTime(100.0) || !self.dragging) &&
// * no inertia action is in progress
self.inertia.is_none() &&
// * the user is not zooming
@@ -1011,9 +1010,7 @@ impl App {
.map_ok(|js_value| {
js_value.dyn_into::<Uint8Array>().unwrap_throw().to_vec()
})
.map_err(|_js_error| {
std::io::Error::new(std::io::ErrorKind::Other, "failed to read")
})
.map_err(|_js_error| std::io::Error::other("failed to read"))
.into_async_read(),
),
};
@@ -1104,9 +1101,7 @@ impl App {
.map_ok(|js_value| {
js_value.dyn_into::<Uint8Array>().unwrap_throw().to_vec()
})
.map_err(|_js_error| {
std::io::Error::new(std::io::ErrorKind::Other, "failed to read")
})
.map_err(|_js_error| std::io::Error::other("failed to read"))
.into_async_read(),
),
};

View File

@@ -79,16 +79,14 @@ impl FieldOfView {
) -> Self {
let mut x_ndc = linspace(-1., 1., NUM_VERTICES_WIDTH + 2);
x_ndc.extend(iter::repeat(1.0).take(NUM_VERTICES_HEIGHT));
x_ndc.extend(iter::repeat_n(1.0, NUM_VERTICES_HEIGHT));
x_ndc.extend(linspace(1., -1., NUM_VERTICES_WIDTH + 2));
x_ndc.extend(iter::repeat(-1.0).take(NUM_VERTICES_HEIGHT));
x_ndc.extend(iter::repeat_n(-1.0, NUM_VERTICES_HEIGHT));
let mut y_ndc = iter::repeat(-1.0)
.take(NUM_VERTICES_WIDTH + 1)
.collect::<Vec<_>>();
let mut y_ndc = iter::repeat_n(-1.0, NUM_VERTICES_WIDTH + 1).collect::<Vec<_>>();
y_ndc.extend(linspace(-1., 1., NUM_VERTICES_HEIGHT + 2));
y_ndc.extend(iter::repeat(1.0).take(NUM_VERTICES_WIDTH));
y_ndc.extend(iter::repeat_n(1.0, NUM_VERTICES_WIDTH));
y_ndc.extend(linspace(1., -1., NUM_VERTICES_HEIGHT + 2));
y_ndc.pop();

View File

@@ -50,7 +50,6 @@ pub fn build_fov_coverage(
let inside_vertex = crate::coosys::apply_coo_system(camera_frame, frame, camera_center);
// Prefer to query from_polygon with depth >= 2
HEALPixCoverage::from_3d_coos(depth, vertices_iter, &inside_vertex)
}

View File

@@ -1,5 +1,5 @@
use cgmath::Vector3;
use al_api::coo_system::CooSystem;
use cgmath::Vector3;
/// This is conversion method returning a transformation
/// matrix when the system requested by the user is not

View File

@@ -230,16 +230,16 @@ fn handle_allsky_file<F: ImageFormat>(
let sx = (src_idx % 27) * d3_tile_allsky_size;
let sy = (src_idx / 27) * d3_tile_allsky_size;
let s = ImageBufferView {
x: sx as i32,
y: sy as i32,
w: d3_tile_allsky_size as i32,
h: d3_tile_allsky_size as i32,
x: sx,
y: sy,
w: d3_tile_allsky_size,
h: d3_tile_allsky_size,
};
let d = ImageBufferView {
x: dx as i32,
y: dy as i32,
w: d3_tile_allsky_size as i32,
h: d3_tile_allsky_size as i32,
w: d3_tile_allsky_size,
h: d3_tile_allsky_size,
};
base_tile.tex_sub(&image, &s, &d);

View File

@@ -87,7 +87,8 @@ impl HEALPixCoverage {
}
pub fn contains_lonlat(&self, lonlat: &LonLatT<f64>) -> bool {
self.0.is_in(lonlat.lon().to_radians(), lonlat.lat().to_radians())
self.0
.is_in(lonlat.lon().to_radians(), lonlat.lat().to_radians())
}
// O(log2(N))

View File

@@ -1,4 +1,4 @@
pub mod cell;
pub mod coverage;
pub mod index_vector;
pub mod utils;
pub mod index_vector;

View File

@@ -23,7 +23,7 @@ impl Inertia {
ampl,
speed: ampl,
axis,
north_up
north_up,
}
}

View File

@@ -121,7 +121,8 @@ pub fn ang_between_lonlat<S: BaseFloat>(lonlat1: LonLatT<S>, lonlat2: LonLatT<S>
let abs_diff_lon = (lonlat1.lon() - lonlat2.lon()).abs();
(lonlat1.lat().sin() * lonlat2.lat().sin()
+ lonlat1.lat().cos() * lonlat2.lat().cos() * abs_diff_lon.cos())
.acos().to_angle()
.acos()
.to_angle()
}
#[inline]
@@ -209,5 +210,6 @@ pub fn unproj_from_screen(
pub fn is_in(v1: &Vector3<f64>, v2: &Vector3<f64>, v: &Vector3<f64>) -> bool {
let theta = crate::math::vector::angle3(v1, v2).abs();
crate::math::vector::angle3(v1, v).abs() < theta && crate::math::vector::angle3(v, v2).abs() < theta
crate::math::vector::angle3(v1, v).abs() < theta
&& crate::math::vector::angle3(v, v2).abs() < theta
}

View File

@@ -16,8 +16,6 @@ impl ProjDef for Ellipse {
let mut p = Vector2::new(xy.x.abs(), xy.y.abs());
let mut ab = Vector2::new(self.a, self.b);
if p.x == 0.0 {
-(self.b - p.y)
} else if p.y == 0.0 {

View File

@@ -2,4 +2,4 @@ pub mod disk;
pub mod ellipse;
pub mod parabola;
pub mod rect;
pub mod triangle;
pub mod triangle;

View File

@@ -5,5 +5,5 @@ pub mod par;
pub mod basic;
pub mod op;
pub mod sdf;
pub mod op;

View File

@@ -1,15 +1,15 @@
use crate::math;
use crate::math::angle::ToAngle;
use cgmath::Vector3;
use cgmath::{BaseFloat, InnerSpace};
use cgmath::{Euler, Quaternion};
use cgmath::Vector3;
#[derive(Clone, Copy, Debug)]
// Internal structure of a rotation, a quaternion
// All operations are done on it
pub struct Rotation<S: BaseFloat>(pub Quaternion<S>);
use cgmath::{Matrix3};
use cgmath::Matrix3;
impl<S> From<&Matrix3<S>> for Rotation<S>
where
S: BaseFloat,

View File

@@ -1,26 +1,26 @@
pub mod bbox;
pub mod region;
pub mod great_circle_arc;
pub mod region;
use super::{PI, TWICE_PI};
#[inline]
pub fn is_in_lon_range(lon0: f64, lon1: f64, lon2: f64) -> bool {
// First version of the code:
// First version of the code:
// ((v2.lon() - v1.lon()).abs() > PI) != ((v2.lon() > coo.lon()) != (v1.lon() > coo.lon()))
//
// Lets note
//
// Lets note
// - lonA = v1.lon()
// - lonB = v2.lon()
// - lon0 = coo.lon()
// When (lonB - lonA).abs() <= PI
// When (lonB - lonA).abs() <= PI
// => lonB > lon0 != lonA > lon0 like in PNPOLY
// A B lonA <= lon0 && lon0 < lonB
// --[++++[--
// B A lonB <= lon0 && lon0 < lonA
//
// But when (lonB - lonA).abs() > PI, then the test should be
// => lonA >= lon0 == lonB >= lon0
// But when (lonB - lonA).abs() > PI, then the test should be
// => lonA >= lon0 == lonB >= lon0
// <=> !(lonA >= lon0 != lonB >= lon0)
// A | B (lon0 < lonB) || (lonA <= lon0)
// --[++|++[--
@@ -32,17 +32,17 @@ pub fn is_in_lon_range(lon0: f64, lon1: f64, lon2: f64) -> bool {
// --]++|++]--
// B | A (lon0 <= lonA) || (lonB < lon0)
//
// So the previous code was bugged in this very specific case:
// So the previous code was bugged in this very specific case:
// - `lon0` has the same value as a vertex being part of:
// - one segment that do not cross RA=0
// - plus one segment crossing RA=0.
// - the point have an odd number of intersections with the polygon
// - the point have an odd number of intersections with the polygon
// (since it will be counted 0 or 2 times instead of 1).
let dlon = lon2 - lon1;
if dlon < 0.0 {
(dlon >= -PI) == (lon2 <= lon0 && lon0 < lon1)
} else {
(dlon <= PI) == (lon1 <= lon0 && lon0 < lon2)
(dlon <= PI) == (lon1 <= lon0 && lon0 < lon2)
}
}
@@ -58,4 +58,3 @@ pub fn distance_from_two_lon(lon1: f64, lon2: f64) -> f64 {
lon2 - lon1
}
}

View File

@@ -115,7 +115,6 @@ pub fn ccw_tri<S: BaseFloat>(a: &[S; 2], b: &[S; 2], c: &[S; 2]) -> bool {
a[0] * b[1] + a[1] * c[0] + b[0] * c[1] - c[0] * b[1] - c[1] * a[0] - b[0] * a[1] >= S::zero()
}
struct PixelBresenhamIter {
x: i32,
y: i32,
@@ -133,17 +132,28 @@ impl PixelBresenhamIter {
fn new(sx: f64, sy: f64, ex: f64, ey: f64) -> Self {
let x = sx.floor() as i32;
let y = sy.floor() as i32;
let xx = ex.floor() as i32;
let yy = ey.floor() as i32;
let dx = (xx - x).abs();
let dx = (xx - x).abs();
let sx = if x < xx { 1 } else { -1 };
let dy = -(yy - y).abs();
let sy = if y < yy { 1 } else { -1 };
let err = dx + dy;
let end = false;
Self { x, y, xx, yy, dx, sx, dy, sy, err, end }
Self {
x,
y,
xx,
yy,
dx,
sx,
dy,
sy,
err,
end,
}
}
}
@@ -177,4 +187,4 @@ impl Iterator for PixelBresenhamIter {
pub fn bresenham(sx: f64, sy: f64, ex: f64, ey: f64) -> impl Iterator<Item = (f64, f64)> {
PixelBresenhamIter::new(sx, sy, ex, ey)
}
}

View File

@@ -10,8 +10,8 @@ use crate::math::lonlat::LonLat;
use crate::math::projection::coo_space::XYScreen;
use crate::math::TWICE_PI;
use crate::math::angle::ToAngle;
use crate::math::angle::AngleFormatter;
use crate::math::angle::ToAngle;
use al_api::angle::Formatter;
use cgmath::Vector2;
use core::ops::Range;
@@ -40,7 +40,7 @@ impl Label {
camera: &CameraViewPort,
projection: &ProjectionType,
fmt: Formatter,
grid_decimal_prec: u8
grid_decimal_prec: u8,
) -> Option<Self> {
let fov = camera.get_field_of_view();
let d = if fov.contains_north_pole() {
@@ -79,12 +79,16 @@ impl Label {
let mut angle = lon.to_angle();
let fmt = match fmt {
Formatter::Decimal => {
AngleFormatter::Decimal { prec: grid_decimal_prec }
Formatter::Decimal => AngleFormatter::Decimal {
prec: grid_decimal_prec,
},
Formatter::Sexagesimal => {
// Sexagesimal formatting for longitudes is HMS
AngleFormatter::Sexagesimal { prec: grid_decimal_prec, plus: false, hours: true }
AngleFormatter::Sexagesimal {
prec: grid_decimal_prec,
plus: false,
hours: true,
}
}
};
angle.set_format(fmt);
@@ -113,7 +117,7 @@ impl Label {
camera: &CameraViewPort,
projection: &ProjectionType,
fmt: Formatter,
grid_decimal_prec: u8
grid_decimal_prec: u8,
) -> Option<Self> {
let lonlat = match options {
LabelOptions::Centered => {
@@ -145,12 +149,16 @@ impl Label {
let mut angle = lat.to_angle();
let fmt = match fmt {
Formatter::Decimal => {
AngleFormatter::Decimal { prec: grid_decimal_prec }
Formatter::Decimal => AngleFormatter::Decimal {
prec: grid_decimal_prec,
},
Formatter::Sexagesimal => {
// Sexagesimal formatting for latitudes is DMS with an optional '+' character
AngleFormatter::Sexagesimal { prec: grid_decimal_prec, plus: true, hours: false }
AngleFormatter::Sexagesimal {
prec: grid_decimal_prec,
plus: true,
hours: false,
}
}
};
angle.set_format(fmt);

View File

@@ -16,7 +16,7 @@ pub fn get_intersecting_meridian(
camera: &CameraViewPort,
projection: &ProjectionType,
fmt: Formatter,
grid_decimal_prec: u8
grid_decimal_prec: u8,
) -> Option<Meridian> {
let fov = camera.get_field_of_view();
if fov.contains_both_poles() {
@@ -27,7 +27,7 @@ pub fn get_intersecting_meridian(
camera,
projection,
fmt,
grid_decimal_prec
grid_decimal_prec,
);
Some(meridian)
} else {
@@ -42,7 +42,7 @@ pub fn get_intersecting_meridian(
camera,
projection,
fmt,
grid_decimal_prec
grid_decimal_prec,
);
Some(meridian)
}
@@ -60,7 +60,15 @@ pub fn get_intersecting_meridian(
lat1..MINUS_HALF_PI
};
Meridian::new(lon, &lat, LabelOptions::OnSide, camera, projection, fmt, grid_decimal_prec)
Meridian::new(
lon,
&lat,
LabelOptions::OnSide,
camera,
projection,
fmt,
grid_decimal_prec,
)
}
2 => {
// full intersection
@@ -77,7 +85,7 @@ pub fn get_intersecting_meridian(
camera,
projection,
fmt,
grid_decimal_prec
grid_decimal_prec,
)
}
_ => Meridian::new(
@@ -87,8 +95,8 @@ pub fn get_intersecting_meridian(
camera,
projection,
fmt,
grid_decimal_prec
)
grid_decimal_prec,
),
};
Some(meridian)
@@ -113,9 +121,17 @@ impl Meridian {
camera: &CameraViewPort,
projection: &ProjectionType,
fmt: Formatter,
grid_decimal_prec: u8
grid_decimal_prec: u8,
) -> Self {
let label = Label::from_meridian(lon, lat, label_options, camera, projection, fmt, grid_decimal_prec);
let label = Label::from_meridian(
lon,
lat,
label_options,
camera,
projection,
fmt,
grid_decimal_prec,
);
// Draw the full parallel
let vertices = crate::renderable::line::great_circle_arc::project(

View File

@@ -12,13 +12,12 @@ use crate::renderable::line;
use core::ops::Range;
pub fn get_intersecting_parallel(
lat: f64,
camera: &CameraViewPort,
projection: &ProjectionType,
fmt: Formatter,
grid_decimal_prec: u8
grid_decimal_prec: u8,
) -> Option<Parallel> {
let fov = camera.get_field_of_view();
if fov.get_bounding_box().get_lon_size() > PI {
@@ -33,7 +32,7 @@ pub fn get_intersecting_parallel(
LabelOptions::Centered,
projection,
fmt,
grid_decimal_prec
grid_decimal_prec,
))
} else {
// Longitude fov < PI
@@ -50,7 +49,7 @@ pub fn get_intersecting_parallel(
LabelOptions::Centered,
projection,
fmt,
grid_decimal_prec
grid_decimal_prec,
))
}
Intersection::Intersect { vertices } => {
@@ -74,7 +73,7 @@ pub fn get_intersecting_parallel(
LabelOptions::OnSide,
projection,
fmt,
grid_decimal_prec
grid_decimal_prec,
))
}
Intersection::Empty => None,
@@ -100,9 +99,17 @@ impl Parallel {
label_options: LabelOptions,
projection: &ProjectionType,
fmt: Formatter,
grid_decimal_prec: u8
grid_decimal_prec: u8,
) -> Self {
let label = Label::from_parallel(lat, lon, label_options, camera, projection, fmt, grid_decimal_prec);
let label = Label::from_parallel(
lat,
lon,
label_options,
camera,
projection,
fmt,
grid_decimal_prec,
);
// Draw the full parallel
let vertices = if lon.end - lon.start > PI {

View File

@@ -106,7 +106,8 @@ impl HiPS3DBuffer {
// Tell if a texture is available meaning all its sub tiles
// must have been written for the GPU
pub fn contains_tile(&self, texture_cell: &HEALPixCell, slice: u16) -> bool {
self.get(texture_cell).is_some_and(|t| t.contains_slice(slice))
self.get(texture_cell)
.is_some_and(|t| t.contains_slice(slice))
}
/// Accessors

View File

@@ -46,7 +46,7 @@ impl HpxTexture3D {
pub fn new(tile_cell: HEALPixCell, time_request: Time) -> Self {
let start_time = None;
let uniq = tile_cell.uniq();
let textures = std::iter::repeat(None).take(512).collect();
let textures = std::iter::repeat_n(None, 512).collect();
let blocks = [0; 512];
let block_indices = Vec::new();
Self {

View File

@@ -1,8 +1,8 @@
use crate::camera::CameraViewPort;
use crate::math::angle::ToAngle;
use crate::math::projection::ProjectionType;
use crate::math::vector::dist2;
use crate::HEALPixCell;
use crate::math::angle::ToAngle;
const M: f64 = 220.0 * 220.0;
@@ -104,7 +104,6 @@ pub(crate) fn subdivide_hpx_cell(
let lat = child_cell.center().1;
let c0 = child_cell.ancestor(child_cell.depth()).idx();
let c3 = child_cell.ancestor(child_cell.depth() - 3);
@@ -115,7 +114,8 @@ pub(crate) fn subdivide_hpx_cell(
let (x, y) = child_cell.get_offset_in_texture_cell(child_cell.depth());
let nside = child_cell.nside() as u32;
let collignon_equatorial_frontier = ((0..=3).contains(&c0) || (8..=11).contains(&c0)) && ((x + y) as i32 - (nside as i32) + 1).abs() <= 1;
let collignon_equatorial_frontier = ((0..=3).contains(&c0) || (8..=11).contains(&c0))
&& ((x + y) as i32 - (nside as i32) + 1).abs() <= 1;
// A HEALPix cell would be distorted if
let hpx_num_sub = if camera.get_aperture() >= 15.0_f64.to_radians() &&
@@ -123,21 +123,23 @@ pub(crate) fn subdivide_hpx_cell(
((0..=3).contains(&c0) || (8..=11).contains(&c0)) &&
// neighbors of cells having only 7 neighbors (the most distorted ones)
c3_s
{
// more specific cells needing a subdivision
2
} else if collignon_equatorial_frontier && c3_s {
// on the collignon/equatorial fence and part of a 3 order cell having only 7 neighbors
1
} else if child_cell.is_on_pole() {
// it lies on a pole
1
} else if child_cell.is_on_base_cell_edges() && lat.abs() >= healpix::TRANSITION_LATITUDE {
// it lies on a frontier between base cells and at a high absolute latitude
1
} else {
0
};
{
// more specific cells needing a subdivision
2
} else if collignon_equatorial_frontier && c3_s {
// on the collignon/equatorial fence and part of a 3 order cell having only 7 neighbors
1
} else if child_cell.is_on_pole() {
// it lies on a pole
1
} else if child_cell.is_on_base_cell_edges()
&& lat.abs() >= healpix::TRANSITION_LATITUDE
{
// it lies on a frontier between base cells and at a high absolute latitude
1
} else {
0
};
// Subdivide one more time if the HEALPix cell is distorted
child_cell.get_children_cells(hpx_num_sub)

View File

@@ -1,6 +1,10 @@
use std::cmp::Ordering;
use std::ops::Range;
pub fn first_and_last_percent<T>(slice: &mut [T], mut first_percent: i32, mut last_percent: i32) -> Range<T>
pub fn first_and_last_percent<T>(
slice: &mut [T],
mut first_percent: i32,
mut last_percent: i32,
) -> Range<T>
where
T: PartialOrd + Copy,
{
@@ -13,11 +17,13 @@ where
let i2 = ((last_percent as f32) * 0.01 * (n as f32)) as usize;
let min_val = {
let (_, min_val, _) = slice.select_nth_unstable_by(i1, |a, b| a.partial_cmp(b).unwrap_or(Ordering::Greater));
let (_, min_val, _) =
slice.select_nth_unstable_by(i1, |a, b| a.partial_cmp(b).unwrap_or(Ordering::Greater));
*min_val
};
let max_val = {
let (_, max_val, _) = slice.select_nth_unstable_by(i2, |a, b| a.partial_cmp(b).unwrap_or(Ordering::Greater));
let (_, max_val, _) =
slice.select_nth_unstable_by(i2, |a, b| a.partial_cmp(b).unwrap_or(Ordering::Greater));
*max_val
};

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@