cargo_leet/leetcode_env/
list.rs

1//! Leetcode Lists Support
2#![allow(clippy::module_name_repetitions)] // the type name is from leetcode, so we cannot modify it
3
4use std::fmt::{Debug, Formatter};
5
6/// Definition for singly-linked list.
7#[derive(PartialEq, Eq)]
8pub struct ListNode {
9    /// The value stored at this node
10    pub val: i32,
11    /// Links to the next node if it exists
12    pub next: Option<Box<ListNode>>,
13}
14
15impl Debug for ListNode {
16    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
17        write!(
18            f,
19            "{} -> {}",
20            self.val,
21            self.next
22                .as_ref()
23                .map_or("None".to_owned(), |next| format!("{next:?}"))
24        )
25    }
26}
27
28impl ListNode {
29    #[inline]
30    #[must_use]
31    /// Creates a new unlinked [`ListNode`] with the value passed
32    pub const fn new(val: i32) -> Self {
33        Self { next: None, val }
34    }
35}
36
37/// Wrapper class to make handling empty lists easier
38#[derive(PartialEq, Eq)]
39pub struct ListHead {
40    head: Option<Box<ListNode>>,
41}
42
43impl Debug for ListHead {
44    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
45        let head: Vec<i32> = self.into();
46        head.fmt(f)
47    }
48}
49
50impl From<ListHead> for Option<Box<ListNode>> {
51    fn from(value: ListHead) -> Self {
52        value.head
53    }
54}
55
56impl From<Option<Box<ListNode>>> for ListHead {
57    fn from(head: Option<Box<ListNode>>) -> Self {
58        Self { head }
59    }
60}
61
62#[allow(clippy::fallible_impl_from)] // Using TryFrom doesn't give us any additional benefits and just makes the code
63// more verbose since this code is used in tests and for input.
64// We need the function to fail if it doesn't match the expected format.
65impl From<Vec<i32>> for ListHead {
66    fn from(values: Vec<i32>) -> Self {
67        let mut result = Self { head: None };
68        let mut curr = &mut result.head;
69        for &num in &values {
70            let node = ListNode::new(num);
71            *curr = Some(Box::new(node));
72            curr = &mut curr.as_mut().unwrap().next;
73        }
74        result
75    }
76}
77
78impl From<&ListHead> for Vec<i32> {
79    fn from(list_head: &ListHead) -> Self {
80        let mut result = vec![];
81        let mut curr = &list_head.head;
82        while let Some(node) = &curr {
83            result.push(node.val);
84            curr = &node.next;
85        }
86        result
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn from_vec_to_linked_list() {
96        // Arrange
97        let start_vec = vec![1, 2, 3, 4, 5];
98        let expected = create_linked_list(1..=5);
99
100        // Act
101        let list_head: ListHead = start_vec.into();
102        let actual: Option<Box<ListNode>> = list_head.into();
103
104        // Assert
105        assert_eq!(actual, expected);
106    }
107
108    fn create_linked_list<I: DoubleEndedIterator<Item = i32>>(values: I) -> Option<Box<ListNode>> {
109        let mut expected = None;
110        for i in values.rev() {
111            let mut new_node = Some(Box::new(ListNode::new(i)));
112            new_node.as_mut().unwrap().next = expected;
113            expected = new_node;
114        }
115        expected
116    }
117
118    #[test]
119    fn from_linked_list_to_vec() {
120        // Arrange
121        let start: ListHead = create_linked_list(1..=5).into();
122        let expected = vec![1, 2, 3, 4, 5];
123
124        // Act
125        let actual: Vec<i32> = (&start).into();
126
127        // Assert
128        assert_eq!(actual, expected);
129    }
130}