Rust to assembly: Recursive linked list merge

Introduction

https://www.howtocodeit.com/articles/rust-ownership-explained-linked-lists

Recurisive linked list merge

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>,
}

pub fn merge(list1: Option<Box<ListNode>>, list2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
    match (list1, list2) {
        (None, None) => None,

        (Some(node), None) | (None, Some(node)) => Some(node),

        (Some(mut node1), Some(mut node2)) => {
            if node1.val < node2.val {
                node1.next = merge(node1.next, Some(node2));

                Some(node1)
            } else {
                node2.next = merge(Some(node1), node2.next);
                Some(node2)
            }
        }
    }
}

Compiler Explorer: recursive linked list merge

https://godbolt.org/z/8osa4vEE4

Convert recursive linked list merge to iterative

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>,
}

pub fn merge(mut list1: Option<Box<ListNode>>, mut list2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
    let mut dummy_head = ListNode { val: 0, next: None };
    let mut tail = &mut dummy_head;

    while let (Some(mut node1), Some(mut node2)) = (list1.take(), list2.take()) {
        if node1.val < node2.val {
            list1 = node1.next.take();
            tail.next = Some(node1);
        } else {
            list2 = node2.next.take();
            tail.next = Some(node2);
        }
        tail = tail.next.as_mut().unwrap();
    }

    if list1.is_some() {
        tail.next = list1;
    } else if list2.is_some() {
        tail.next = list2;
    }

    dummy_head.next
}

Compiler Explorer: iterative linked list merge

https://godbolt.org/z/T3oh943v9

Tail call recursive linked list merge

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>,
}

pub fn merge(list1: Option<Box<ListNode>>, list2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
    fn merge_tail(
        list1: Option<Box<ListNode>>,
        list2: Option<Box<ListNode>>,
        acc: Option<Box<ListNode>>,
    ) -> Option<Box<ListNode>> {
        match (list1, list2) {
            (None, None) => acc,

            (Some(node), None) | (None, Some(node)) => {
                append(acc, Some(node)) // append remaining node to accumulator
            }

            (Some(mut node1), Some(mut node2)) => {
                if node1.val < node2.val {
                    let next1 = node1.next.take();
                    let new_acc = append(acc, Some(node1));
                    merge_tail(next1, Some(node2), new_acc)
                } else {
                    let next2 = node2.next.take();
                    let new_acc = append(acc, Some(node2));
                    merge_tail(Some(node1), next2, new_acc)
                }
            }
        }
    }

    fn append(
        mut acc: Option<Box<ListNode>>,
        node: Option<Box<ListNode>>,
    ) -> Option<Box<ListNode>> {
        if acc.is_none() {
            return node;
        }

        let mut current = acc.as_mut().unwrap();
        while let Some(ref mut next) = current.next {
            current = next;
        }
        current.next = node;

        acc
    }

    merge_tail(list1, list2, None)
}

Compiler Explorer: tail call recursive linked list merge

https://godbolt.org/z/77hao5s48