restructured algorithms, added tests and tests in actions
This commit is contained in:
parent
63e8214974
commit
3a05b90f09
12 changed files with 395 additions and 268 deletions
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
|
@ -15,6 +15,8 @@ jobs:
|
|||
toolchain: stable
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
- name : Run Tests
|
||||
run: cargo test --all
|
||||
- name: Add wasm with rustup
|
||||
run: |
|
||||
rustup target add wasm32-unknown-unknown
|
||||
|
|
265
src/Algorithm.rs
265
src/Algorithm.rs
|
@ -1,265 +0,0 @@
|
|||
|
||||
use crate::GuiHookVec::GuiVec;
|
||||
use crate::GuiHookVec::SortingList;
|
||||
|
||||
|
||||
|
||||
|
||||
use std::collections::BinaryHeap;
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Algorithm{
|
||||
|
||||
}
|
||||
|
||||
impl Algorithm{
|
||||
|
||||
pub async fn run(length:i32, delay:f32, functionName:String){
|
||||
let mut list:GuiVec = SortingList::new(length, delay);
|
||||
list.randomize();
|
||||
|
||||
|
||||
match functionName.as_str() {
|
||||
"insertSort" => Algorithm::insertSort(&mut list).await,
|
||||
"bubbleSort" => Algorithm::bubbleSort(&mut list).await,
|
||||
"bogoSort" => Algorithm::bogoSort(&mut list).await,
|
||||
"cocktailShaker" => Algorithm::cocktailShaker(&mut list).await,
|
||||
"binaryHeap" => Algorithm::binaryHeap(&mut list).await,
|
||||
"quickSort" => Algorithm::quickSort(&mut list).await,
|
||||
"radixSort" => Algorithm::radixSort(&mut list).await,
|
||||
"stalinSort" => Algorithm::stalinSort(&mut list).await,
|
||||
_ => panic!("No algorithm with that name implemented!")
|
||||
}
|
||||
|
||||
|
||||
|
||||
if !list.done{
|
||||
list.show().await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn insertSort(list:&mut impl SortingList){
|
||||
for index in 0..list.len(){
|
||||
let mut j = index;
|
||||
while j>0 && list.lessThan(j, j-1){
|
||||
if list.swap(j, j - 1).await {return};
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn stalinSort(list:&mut impl SortingList){
|
||||
|
||||
let mut cur = 1;
|
||||
loop{
|
||||
if cur == list.len() {
|
||||
break;
|
||||
}
|
||||
if list.lessThan(cur, cur-1){
|
||||
let mut temp = list.get(cur).clone();
|
||||
temp.position = 0;
|
||||
if list.set(cur, temp).await {return};
|
||||
}else{
|
||||
cur += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
pub async fn bubbleSort(list:&mut impl SortingList){
|
||||
let n = list.len();
|
||||
for i in 0..n {
|
||||
for j in 0..(n - i - 1) {
|
||||
if list.lessThan(j + 1, j) {
|
||||
if list.swap(j, j + 1).await {return};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub async fn bogoSort(list:&mut impl SortingList){
|
||||
|
||||
loop{
|
||||
if list.swap(0,0).await {return};
|
||||
if list.isSorted() {
|
||||
break;
|
||||
}
|
||||
list.randomize();
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn cocktailShaker(list:&mut impl SortingList){
|
||||
let mut lowerBound = 0;
|
||||
let mut upperBound = list.len()-1;
|
||||
let mut swapped = true;
|
||||
while swapped{
|
||||
swapped = false;
|
||||
for i in lowerBound..upperBound {
|
||||
if list.lessThan(i+1, i) {
|
||||
if list.swap(i+1, i).await {return};
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
if !swapped{
|
||||
break;
|
||||
}
|
||||
swapped = false;
|
||||
upperBound = upperBound-1;
|
||||
for i in ((lowerBound)..(upperBound)).rev() {
|
||||
if list.lessThan(i+1, i) {
|
||||
if list.swap(i+1, i).await {return};
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
lowerBound = lowerBound+1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
pub async fn binaryHeap(list:&mut impl SortingList){
|
||||
|
||||
let mut indexMap:HashMap<i32, usize> = HashMap::new();
|
||||
let mut binHeap:BinaryHeap<i32> = BinaryHeap::new();
|
||||
|
||||
let mut ind = 0;
|
||||
for bar in list.elements(){
|
||||
binHeap.push(bar.position);
|
||||
indexMap.insert(bar.position, ind);
|
||||
ind += 1;
|
||||
}
|
||||
for i in (0..list.len()).rev(){
|
||||
let bar = binHeap.pop().unwrap();
|
||||
let barIndex = *indexMap.get(&bar).unwrap();
|
||||
if list.swap(i, barIndex).await {return};
|
||||
let temp = list.get(barIndex).position;
|
||||
indexMap.insert(temp, barIndex);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub async fn partition(list:&mut impl SortingList, mut low:usize, mut high:usize, p:i32) -> i32{
|
||||
let mut pIndex = low;
|
||||
|
||||
for i in low..high{
|
||||
if list.lessThanEqual(i, p){
|
||||
if list.swap(i, pIndex).await {return -1}
|
||||
pIndex += 1;
|
||||
}
|
||||
}
|
||||
if list.swap(pIndex, high).await {return -1};
|
||||
|
||||
return pIndex as i32
|
||||
}
|
||||
|
||||
|
||||
pub async fn quickSort(list:&mut impl SortingList) {
|
||||
let mut stack:Vec<(usize,usize)> = Vec::new();
|
||||
|
||||
let start = 0;
|
||||
let end = list.len()-1;
|
||||
|
||||
stack.push((start,end));
|
||||
|
||||
while stack.len() > 0{
|
||||
let (start,end) = stack.pop().unwrap();
|
||||
|
||||
let p = list.get(end).position;
|
||||
let temp = Algorithm::partition(list, start, end, p).await;
|
||||
let pivot = if temp >= 0 {temp} else {return};
|
||||
|
||||
if pivot != 0 && pivot as usize -1 > start{
|
||||
|
||||
stack.push((start,pivot as usize-1));
|
||||
}
|
||||
|
||||
if pivot as usize + 1 < end{
|
||||
stack.push((pivot as usize +1, end))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub async fn radixSort(list:&mut impl SortingList) {
|
||||
|
||||
let mut max = usize::MAX;
|
||||
for i in list.getListClone().into_iter().map(|x| x.position.to_string()){
|
||||
if max < i.len(){
|
||||
max = i.len();
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..(max){
|
||||
if Algorithm::radix(list, i).await {return};
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn radix(list:&mut impl SortingList, radix:usize) -> bool{
|
||||
let mut bucket = vec![vec![];10];
|
||||
|
||||
for (i, bar) in list.elements().enumerate(){
|
||||
|
||||
let cur = bar.position.to_string().chars().rev().collect::<Vec<char>>();
|
||||
if cur.len() > radix{
|
||||
bucket[cur[radix].to_digit(10).unwrap() as usize].push(i);
|
||||
}else{
|
||||
bucket[0].push(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
let mut sortedIndexes = Vec::new();
|
||||
for elements in bucket.into_iter(){
|
||||
for i in elements{
|
||||
sortedIndexes.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
let mut listClone = list.getListClone();
|
||||
let mut count = 0;
|
||||
for i in sortedIndexes.clone(){
|
||||
if list.set(count, listClone[i]).await {return true};
|
||||
count += 1;
|
||||
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use crate::GuiHookVec::NonGuiVec;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
macro_rules! aw {
|
||||
($e:expr) => {
|
||||
tokio_test::block_on($e)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_str_len_async_2() {
|
||||
let mut list:NonGuiVec = SortingList::new(1000,0.0);
|
||||
aw!(Algorithm::insertSort(&mut list));
|
||||
assert_eq!( list.isSorted(), true);
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ use macroquad::time::{get_frame_time, get_fps};
|
|||
use macroquad::ui::root_ui;
|
||||
use macroquad::window::{next_frame, screen_height, screen_width};
|
||||
use crate::BarPlugin::Bar;
|
||||
use crate::Algorithm::Algorithm;
|
||||
use crate::algorithm::Algorithm;
|
||||
|
||||
|
||||
|
||||
|
|
47
src/algorithm.rs
Normal file
47
src/algorithm.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
mod radixSort;
|
||||
mod insertSort;
|
||||
mod bubbleSort;
|
||||
mod binaryHeap;
|
||||
mod coctailShaker;
|
||||
mod quickSort;
|
||||
mod bogoSort;
|
||||
|
||||
|
||||
use crate::GuiHookVec::GuiVec;
|
||||
use crate::GuiHookVec::SortingList;
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Algorithm{
|
||||
|
||||
}
|
||||
|
||||
impl Algorithm{
|
||||
|
||||
pub async fn run(length:i32, delay:f32, functionName:String){
|
||||
let mut list:GuiVec = SortingList::new(length, delay);
|
||||
list.randomize();
|
||||
|
||||
|
||||
match functionName.as_str() {
|
||||
"insertSort" => insertSort::insertSort(&mut list).await,
|
||||
"bubbleSort" => bubbleSort::bubbleSort(&mut list).await,
|
||||
"bogoSort" => bogoSort::bogoSort(&mut list).await,
|
||||
"cocktailShaker" => coctailShaker::cocktailShaker(&mut list).await,
|
||||
"binaryHeap" => binaryHeap::binaryHeap(&mut list).await,
|
||||
"quickSort" => quickSort::quickSort(&mut list).await,
|
||||
"radixSort" => radixSort::radixSort(&mut list).await,
|
||||
_ => panic!("No algorithm with that name implemented!")
|
||||
}
|
||||
|
||||
|
||||
|
||||
if !list.done{
|
||||
list.show().await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
47
src/algorithm/binaryHeap.rs
Normal file
47
src/algorithm/binaryHeap.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
use std::collections::{HashMap, BinaryHeap};
|
||||
|
||||
use crate::GuiHookVec::SortingList;
|
||||
|
||||
pub async fn binaryHeap(list:&mut impl SortingList){
|
||||
|
||||
let mut indexMap:HashMap<i32, usize> = HashMap::new();
|
||||
let mut binHeap:BinaryHeap<i32> = BinaryHeap::new();
|
||||
|
||||
let mut ind = 0;
|
||||
for bar in list.elements(){
|
||||
binHeap.push(bar.position);
|
||||
indexMap.insert(bar.position, ind);
|
||||
ind += 1;
|
||||
}
|
||||
for i in (0..list.len()).rev(){
|
||||
let bar = binHeap.pop().unwrap();
|
||||
let barIndex = *indexMap.get(&bar).unwrap();
|
||||
if list.swap(i, barIndex).await {return};
|
||||
let temp = list.get(barIndex).position;
|
||||
indexMap.insert(temp, barIndex);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use crate::GuiHookVec::NonGuiVec;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
macro_rules! aw {
|
||||
($e:expr) => {
|
||||
tokio_test::block_on($e)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn binartHeap_correct() {
|
||||
let mut list:NonGuiVec = SortingList::new(1000,0.0);
|
||||
aw!(binaryHeap(&mut list));
|
||||
assert_eq!( list.isSorted(), true);
|
||||
}
|
||||
}
|
33
src/algorithm/bogoSort.rs
Normal file
33
src/algorithm/bogoSort.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use crate::GuiHookVec::SortingList;
|
||||
|
||||
pub async fn bogoSort(list:&mut impl SortingList){
|
||||
|
||||
loop{
|
||||
if list.swap(0,0).await {return};
|
||||
if list.isSorted() {
|
||||
break;
|
||||
}
|
||||
list.randomize();
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use crate::GuiHookVec::NonGuiVec;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
macro_rules! aw {
|
||||
($e:expr) => {
|
||||
tokio_test::block_on($e)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bogoSort_correct_this_is_a_meme() {
|
||||
let mut list:NonGuiVec = SortingList::new(5,0.0);
|
||||
aw!(bogoSort(&mut list));
|
||||
assert_eq!( list.isSorted(), true);
|
||||
}
|
||||
}
|
34
src/algorithm/bubbleSort.rs
Normal file
34
src/algorithm/bubbleSort.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use crate::GuiHookVec::SortingList;
|
||||
|
||||
pub async fn bubbleSort(list:&mut impl SortingList){
|
||||
let n = list.len();
|
||||
for i in 0..n {
|
||||
for j in 0..(n - i - 1) {
|
||||
if list.lessThan(j + 1, j) {
|
||||
if list.swap(j, j + 1).await {return};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use crate::GuiHookVec::NonGuiVec;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
macro_rules! aw {
|
||||
($e:expr) => {
|
||||
tokio_test::block_on($e)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bubblesort_correct() {
|
||||
let mut list:NonGuiVec = SortingList::new(1000,0.0);
|
||||
aw!(bubbleSort(&mut list));
|
||||
assert_eq!( list.isSorted(), true);
|
||||
}
|
||||
}
|
53
src/algorithm/coctailShaker.rs
Normal file
53
src/algorithm/coctailShaker.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
use crate::GuiHookVec::SortingList;
|
||||
|
||||
pub async fn cocktailShaker(list:&mut impl SortingList){
|
||||
let mut lowerBound = 0;
|
||||
let mut upperBound = list.len()-1;
|
||||
let mut swapped = true;
|
||||
while swapped{
|
||||
swapped = false;
|
||||
for i in lowerBound..upperBound {
|
||||
if list.lessThan(i+1, i) {
|
||||
if list.swap(i+1, i).await {return};
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
if !swapped{
|
||||
break;
|
||||
}
|
||||
swapped = false;
|
||||
upperBound = upperBound-1;
|
||||
for i in ((lowerBound)..(upperBound)).rev() {
|
||||
if list.lessThan(i+1, i) {
|
||||
if list.swap(i+1, i).await {return};
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
lowerBound = lowerBound+1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use crate::GuiHookVec::NonGuiVec;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
macro_rules! aw {
|
||||
($e:expr) => {
|
||||
tokio_test::block_on($e)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn coctailshakersort_correct() {
|
||||
let mut list:NonGuiVec = SortingList::new(1000,0.0);
|
||||
aw!(cocktailShaker(&mut list));
|
||||
assert_eq!( list.isSorted(), true);
|
||||
}
|
||||
}
|
33
src/algorithm/insertSort.rs
Normal file
33
src/algorithm/insertSort.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use crate::GuiHookVec::SortingList;
|
||||
|
||||
pub async fn insertSort(list:&mut impl SortingList){
|
||||
for index in 0..list.len(){
|
||||
let mut j = index;
|
||||
while j>0 && list.lessThan(j, j-1){
|
||||
if list.swap(j, j - 1).await {return};
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use crate::GuiHookVec::NonGuiVec;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
macro_rules! aw {
|
||||
($e:expr) => {
|
||||
tokio_test::block_on($e)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insertsort_correct() {
|
||||
let mut list:NonGuiVec = SortingList::new(1000,0.0);
|
||||
aw!(insertSort(&mut list));
|
||||
assert_eq!( list.isSorted(), true);
|
||||
}
|
||||
}
|
69
src/algorithm/quickSort.rs
Normal file
69
src/algorithm/quickSort.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
use crate::GuiHookVec::SortingList;
|
||||
|
||||
|
||||
|
||||
pub async fn quickSort(list:&mut impl SortingList) {
|
||||
let mut stack:Vec<(usize,usize)> = Vec::new();
|
||||
|
||||
let start = 0;
|
||||
let end = list.len()-1;
|
||||
|
||||
stack.push((start,end));
|
||||
|
||||
while stack.len() > 0{
|
||||
let (start,end) = stack.pop().unwrap();
|
||||
|
||||
let p = list.get(end).position;
|
||||
let temp = partition(list, start, end, p).await;
|
||||
let pivot = if temp >= 0 {temp} else {return};
|
||||
|
||||
if pivot != 0 && pivot as usize -1 > start{
|
||||
|
||||
stack.push((start,pivot as usize-1));
|
||||
}
|
||||
|
||||
if pivot as usize + 1 < end{
|
||||
stack.push((pivot as usize +1, end))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
async fn partition(list:&mut impl SortingList, mut low:usize, mut high:usize, p:i32) -> i32{
|
||||
let mut pIndex = low;
|
||||
|
||||
for i in low..high{
|
||||
if list.lessThanEqual(i, p){
|
||||
if list.swap(i, pIndex).await {return -1}
|
||||
pIndex += 1;
|
||||
}
|
||||
}
|
||||
if list.swap(pIndex, high).await {return -1};
|
||||
|
||||
return pIndex as i32
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use crate::GuiHookVec::NonGuiVec;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
macro_rules! aw {
|
||||
($e:expr) => {
|
||||
tokio_test::block_on($e)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quicksort_correct() {
|
||||
let mut list:NonGuiVec = SortingList::new(1000,0.0);
|
||||
aw!(quickSort(&mut list));
|
||||
assert_eq!( list.isSorted(), true);
|
||||
}
|
||||
}
|
74
src/algorithm/radixSort.rs
Normal file
74
src/algorithm/radixSort.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
use crate::GuiHookVec::SortingList;
|
||||
|
||||
|
||||
|
||||
pub async fn radixSort(list:&mut impl SortingList) {
|
||||
|
||||
let mut max = usize::MIN;
|
||||
for i in list.getListClone().into_iter().map(|x| x.position.to_string()){
|
||||
|
||||
if max < i.len(){
|
||||
max = i.len();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for i in 0..(max){
|
||||
if radix(list, i).await {return};
|
||||
}
|
||||
}
|
||||
|
||||
async fn radix(list:&mut impl SortingList, radix:usize) -> bool{
|
||||
let mut bucket = vec![vec![];10];
|
||||
|
||||
for (i, bar) in list.elements().enumerate(){
|
||||
|
||||
let cur = bar.position.to_string().chars().rev().collect::<Vec<char>>();
|
||||
if cur.len() > radix{
|
||||
bucket[cur[radix].to_digit(10).unwrap() as usize].push(i);
|
||||
}else{
|
||||
bucket[0].push(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
let mut sortedIndexes = Vec::new();
|
||||
for elements in bucket.into_iter(){
|
||||
for i in elements{
|
||||
sortedIndexes.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
let mut listClone = list.getListClone();
|
||||
let mut count = 0;
|
||||
for i in sortedIndexes.clone(){
|
||||
if list.set(count, listClone[i]).await {return true};
|
||||
count += 1;
|
||||
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use crate::GuiHookVec::NonGuiVec;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
macro_rules! aw {
|
||||
($e:expr) => {
|
||||
tokio_test::block_on($e)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn radixsort_correct() {
|
||||
let mut list:NonGuiVec = SortingList::new(10000,0.0);
|
||||
aw!(radixSort(&mut list));
|
||||
assert_eq!( list.isSorted(), true);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
mod BarPlugin;
|
||||
mod GuiHookVec;
|
||||
mod Algorithm;
|
||||
mod algorithm;
|
||||
|
||||
use macroquad::prelude::*;
|
||||
use macroquad::prelude::scene::clear;
|
||||
|
@ -66,7 +66,7 @@ async fn main() {
|
|||
|
||||
|
||||
if algo != ""{
|
||||
Algorithm::Algorithm::run(length, 1.0, algo.to_string()).await;
|
||||
algorithm::Algorithm::run(length, 1.0, algo.to_string()).await;
|
||||
}
|
||||
next_frame().await
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue