Blog: Why not to use Rust

I don't currently have access to my PC to show my code but here's a rough example in C#. For Predicate I used F: Fn(&T) -> bool and Action I used FnMut(&mut T). BoundingSphere I was able to roughly write to Rust already

public void Select(BoundingSphere sphere, Predicate<T> predicate, List<T> result)
        {
            if (result == null) return;
            if (Bound.Intersects(sphere))
            {
                if (m_childs.Length == 0)
                {
                    var items = m_items;
                    for (int index = 0; index < items.Length; index++)
                    {
                        var item = items[index];
                        if (item == null)
                            break;
                        if (sphere.Contains(item.Position) && (predicate?.Invoke(item) ?? true))
                            result.Add(item);
                    }
                }
                else
                {
                    for (int index = 0; index < m_childs.Length; index++)
                        m_childs[index].Select(sphere, predicate, result);
                }
            }
            Parent?.Select(sphere, predicate, result);
        }

        public void ForEach(BoundingSphere sphere, Predicate<T> predicate, Action<T> action)
        {
            if (action == null) return;
            if (Bound.Intersects(sphere))
            {
                if (m_childs.Length == 0)
                {
                    var items = m_items;
                    for (int index = 0; index < items.Length; index++)
                    {
                        var item = items[index];
                        if (item == null)
                            break;
                        if (sphere.Contains(item.Position) && (predicate?.Invoke(item) ?? true))
                            action(item);
                    }
                }
                else
                {
                    for (int index = 0; index < m_childs.Length; index++)
                        m_childs[index].ForEach(sphere, predicate, action);
                }
            }
            Parent?.ForEach(sphere, predicate, action);
        }

Apologies if I've overly reduced your real code, but would something like the below work for you:

struct Foo {
    children: Vec<Foo>,
    touched: bool
}

fn for_each<F: FnMut(&mut Foo)>(f: &mut Foo, action: &mut F) {
    action(f);
    for child in f.children.iter_mut() {
       for_each(child, action);
    }
}

fn main() {
   let touched = false;
   let mut f = Foo {children: vec![Foo {children: vec![], touched}], touched};
   for_each(&mut f, &mut |x| x.touched = true);
   
}
1 Like

Appreciated. I was mainly concerned about borrow/ownership here because in the C# code it involves working on a reference mutably and I feared it would involve multiple mutable borrows

Valid concern! :slight_smile:

In a nutshell, the way Rust passes a &mut to a function (that also takes a &mut) is via reborrowing. Reborrowing is automatic but it's essentially &mut *ref. A reborrow makes the previous mutable reference non live (kind of a "freeze" action, if you will). Once a reborrow ends, the previous mutable reference is live again. So, as long as you don't attempt to reborrow mutably while there's a live borrow, things will just work.

You can search for "rust reborrow" and get more info on it if you'd like.

4 Likes

C++ compiler support - cppreference.com has data on this. C++11 compiler support is quite good now. Note also that the most popular compiler in HPC is GCC.