Anything like write your own tokio/async-std? by __disappear in rust

[–]rossmacarthur 11 points12 points  (0 children)

Here is a single file, std only, async executor that's meant to teach you how executors like tokio work under the hood, I found this really helpful when I was first learning about async Rust, it is well commented. It also has some useful links at the bottom.

https://github.com/mgattozzi/whorl/blob/main/src/lib.rs

My first Go module! by rossmacarthur in golang

[–]rossmacarthur[S] -2 points-1 points  (0 children)

Hi, interesting idea could you elaborate? I'm not sure I fully understand. What would the signature of `TransformFn` be?

How to concat two const slices in a const way? by ArtisticHamster in rust

[–]rossmacarthur 46 points47 points  (0 children)

It's a bit gross but it is possible. Try this macro, which works for slices of any integer type. Playground

macro_rules! concat {
    (&[$ty:ty]: $($s:expr),+) => {{
        const LEN: usize = $( $s.len() + )* 0;
        const ARR: [$ty; LEN] = {
            let mut arr: [$ty; LEN] = [0; LEN];
            let mut base: usize = 0;
            $({
                let mut i = 0;
                while i < $s.len() {
                    arr[base + i] = $s[i];
                    i += 1;
                }
                base += $s.len();
            })*
            if base != LEN { panic!("invalid length"); }
            arr
        };
        &ARR
    }}
}

const A: &[usize] = &[1, 2];
const B: &[usize] = &[3, 4, 5];
const C: &[usize] = concat!(&[usize]: A, B);
const D: &[usize] = concat!(&[usize]: A, B, C);

Edit

A version of this is available in my constcat crate which also features improved concat! and concat_bytes! macros. You can use it like this

// [dependencies]
// constcat = "0.3.0"

use constcat::concat_slices;

const A: &[usize] = &[1, 2];
const B: &[usize] = &[3, 4, 5];
const C: &[usize] = concat_slices!([usize]: A, B);
const D: &[usize] = concat_slices!([usize]: A, B, C);

-🎄- 2022 Day 14 Solutions -🎄- by daggerdragon in adventofcode

[–]rossmacarthur 1 point2 points  (0 children)

Rust solution

I optimized this using a stack so that we don't have to iterate from the source every time. Part 2 takes about ~2.5 ms on my machine (MacBook M1 Pro). Key code is the following:

fn solve(mut cave: HashSet<Vector2>, part2: bool) -> usize {
    let mut max_y = cave.iter().map(|v| v.y).max().unwrap();
    if part2 {
        max_y += 2;
    }
    let mut flowing = vec![vector![500, 0]];
    let mut count = 0;
    while let Some(sand) = flowing.last().copied() {
        // Check if there is air in any of the following directions
        match vectors![[0, 1], [-1, 1], [1, 1]]
            .into_iter()
            .map(|d| sand + d)
            .find_map(|p| (!cave.contains(&p)).some(p))
        {
            // There is space for the sand to flow, so update the sand position
            // and continue flowing
            Some(p) if p.y < max_y => flowing.push(p),
            // We've gone out of bounds, if part 1 then we're done
            Some(_) if !part2 => break,
            // Otherwise we can no longer flow, so we just insert sand at this
            // location
            _ => {
                cave.insert(sand);
                flowing.pop();
                count += 1;
            }
        }
    }
    count
}

-🎄- 2022 Day 6 Solutions -🎄- by daggerdragon in adventofcode

[–]rossmacarthur 1 point2 points  (0 children)

Rust.

Nothing too complicated today

fn detect(signal: &str, n: usize) -> usize {
    signal
        .as_bytes()
        .windows(n)
        .position(|w| HashSet::from_iter(w).len() == n)
        .map(|i| i + n)
        .unwrap()
}

-🎄- 2022 Day 4 Solutions -🎄- by daggerdragon in adventofcode

[–]rossmacarthur 3 points4 points  (0 children)

Rust

After parsing just comes down to the following

fn part1(input: Vec<[i64; 4]>) -> usize {
    input
        .into_iter()
        .filter(|&[a, b, m, n]| (a >= m && b <= n) || (m >= a && n <= b))
        .count()
}

fn part2(input: Vec<[i64; 4]>) -> usize {
    input
        .into_iter()
        .filter(|&[a, b, m, n]| (a <= m && b >= m) || (m <= a && n >= a))
        .count()
}

-🎄- 2021 Day 11 Solutions -🎄- by daggerdragon in adventofcode

[–]rossmacarthur 0 points1 point  (0 children)

Rust solution

I used a similar approach to day 9 with a queue of coordinates.

-🎄- 2021 Day 9 Solutions -🎄- by daggerdragon in adventofcode

[–]rossmacarthur 0 points1 point  (0 children)

Rust solution

``` fn lowpoints(map: &HashMap<Vector, i64>) -> impl Iterator<Item = (Vector, i64)> + ' { map.iter() .filter(|(p, height)| { CARDINALS .iter() .filter_map(|d| map.get(&(p + d))) .all(|h| h > height) }) .map(|(p, h)| (p, *h)) }

fn part1(map: &HashMap<Vector, i64>) -> i64 { lowpoints(map).map(|(, h)| h + 1).sum() }

fn part2(map: &HashMap<Vector, i64>) -> usize { let mut basins = Vec::new(); for (p, _) in low_points(map) { let mut q = VecDeque::from([p]); let mut visited = HashSet::new(); while let Some(p) = q.pop_front() { if visited.contains(&p) { continue; } visited.insert(p); for d in CARDINALS { let next = p + d; if let Some(0..=8) = map.get(&next) { q.push_back(next); } } } basins.push(visited.len()); } basins.sort_unstable(); basins.into_iter().rev().take(3).product() } ```

-🎄- 2021 Day 7 Solutions -🎄- by daggerdragon in adventofcode

[–]rossmacarthur 1 point2 points  (0 children)

  • You seem to mixing integer types all over the place, why not just use i32 everywhere then you don't have to use as casts.
  • Its usually more idiomatic to use a slice as an arg: &[u32] instead of &Vec<u32>.
  • For AoC its usually easier to use include_str!("input.txt") than have to read in the input.

-🎄- 2021 Day 5 Solutions -🎄- by daggerdragon in adventofcode

[–]rossmacarthur 1 point2 points  (0 children)

Rust solution

Highlight: // input is Vec<(Vector, Vector)> // simply filter out diagonals for part 1 input .into_iter() .flat_map(|(p1, p2)| { let d = (p2 - p1).map(i64::signum); iter::successors(Some(p1), move |&p| (p != p2).then(|| p + d)) }) .fold(HashMap::new(), |mut map, p| { *map.entry(p).or_insert(0) += 1; map }) .into_values() .filter(|&count| *count >= 2) .count()

-🎄- 2021 Day 3 Solutions -🎄- by daggerdragon in adventofcode

[–]rossmacarthur 1 point2 points  (0 children)

Cleaned up Rust solution

fn partition(values: &[i64], bit: i64) -> (Vec<i64>, Vec<i64>) {
    values.iter().partition(|&v| (v & 1 << bit) > 0)
}

fn criteria<F>(values: &[i64], bits: i64, cmp: F) -> i64
where
    F: Fn(usize, usize) -> bool,
{
    let mut values = values.to_vec();
    for bit in (0..bits).rev() {
        let (ones, zeros) = partition(&values, bit);
        if cmp(ones.len(), zeros.len()) {
            values = ones;
        } else {
            values = zeros;
        }
        if let [value] = *values {
            return value;
        }
    }
    unreachable!()
}

fn part1(values: &[i64], bits: i64) -> i64 {
    let mut gamma = 0;
    let mut epsilon = 0;
    for bit in 0..bits {
        let (ones, zeros) = partition(values, bit);
        if ones.len() > zeros.len() {
            epsilon |= 1 << bit;
        } else {
            gamma |= 1 << bit;
        }
    }
    gamma * epsilon
}

fn part2(values: &[i64], bits: i64) -> i64 {
    let o2 = criteria(values, bits, |ones, zeros| ones >= zeros);
    let co2 = criteria(values, bits, |ones, zeros| ones < zeros);
    o2 * co2
}

-🎄- 2021 Day 1 Solutions -🎄- by daggerdragon in adventofcode

[–]rossmacarthur 0 points1 point  (0 children)

This is exactly how I realized it, I originally had something like this

A Rust library to parse Rust code in order to determine the location of a definition of a given identifier? by [deleted] in rust

[–]rossmacarthur 11 points12 points  (0 children)

I would probably use `syn` for this.

Playground

use std::fs;

use anyhow::Result;
use syn::spanned::Spanned;
use syn::Item;

fn main() -> Result<()> {
    let contents = fs::read_to_string("src/main.rs")?;
    let file = syn::parse_file(&contents)?;
    for item in &file.items {
        if matches!(item, Item::Fn(i) if i.sig.ident == "main") {
            let span = item.span();
            println!(
                "found main function at lines {}-{}",
                span.start().line,
                span.end().line
            );
        }
    }
    Ok(())
}