1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45/// The index associated with a call, that is guaranteed to be unique for the lifetime of the call,
6/// but will be recycled after the call is released.
7pub type Idx = usize;
89/// A collection designed for the specific requirements of storing Calls with an associated index.
10///
11/// The requirements found in HFP v1.8, Section 4.34.2, "+CLCC":
12///
13/// * Each call is assigned a number starting at 1.
14/// * Calls hold their number until they are released.
15/// * New calls take the lowest available number.
16///
17/// Note: "Insert" is a O(n) operation in order to simplify the implementation.
18/// This data structure is best suited towards small n for this reason.
19pub struct List<T> {
20 inner: Vec<Option<T>>,
21}
2223impl<T> Default for List<T> {
24fn default() -> Self {
25Self { inner: Vec::default() }
26 }
27}
2829impl<T> List<T> {
30/// Insert a new value into the list, returning an index that is guaranteed to be unique until
31 /// the value is removed from the list.
32pub fn insert(&mut self, value: T) -> Idx {
33let index = if let Some(index) = self.inner.iter_mut().position(|v| v.is_none()) {
34self.inner[index] = Some(value);
35 index
36 } else {
37self.inner.push(Some(value));
38self.inner.len() - 1
39};
4041Self::to_call_index(index)
42 }
4344/// Retrieve a value by index. Returns `None` if the index does not point to a value.
45pub fn get(&self, index: Idx) -> Option<&T> {
46match Self::to_internal_index(index) {
47Some(index) => self.inner.get(index).map(|v| v.as_ref()).unwrap_or(None),
48None => None,
49 }
50 }
5152/// Retrieve a mutable reference to a value by index. Returns `None` if the index does not point
53 /// to a value.
54pub fn get_mut(&mut self, index: Idx) -> Option<&mut T> {
55match Self::to_internal_index(index) {
56Some(index) => self.inner.get_mut(index).map(|v| v.as_mut()).unwrap_or(None),
57None => None,
58 }
59 }
6061/// Remove a value by index. Returns `None` if the value did not point to a value.
62pub fn remove(&mut self, index: Idx) -> Option<T> {
63match Self::to_internal_index(index) {
64Some(index) => self.inner.get_mut(index).map(|v| v.take()).unwrap_or(None),
65None => None,
66 }
67 }
6869/// Return an iterator of the calls and associated call indices.
70pub fn calls(&self) -> impl Iterator<Item = (Idx, &T)> + Clone {
71self.inner
72 .iter()
73 .enumerate()
74 .flat_map(|(i, entry)| entry.as_ref().map(|v| (Self::to_call_index(i), v)))
75 }
7677/// Convert a `Idx` to the internal index used to locate a call.
78 ///
79 /// The Idx for a call starts at 1 instead of 0, so the internal index must be decremented
80 /// after being received by the user.
81 ///
82 /// Returns `None` if `index` is 0 because 0 is an invalid index.
83fn to_internal_index(index: Idx) -> Option<usize> {
84 (index != 0).then(|| index - 1)
85 }
8687/// Convert the internal index for a call to the external `Idx`.
88 /// The Idx for a call starts at 1 instead of 0, so the internal index must be incremented
89 /// before being returned to the user.
90fn to_call_index(internal: usize) -> Idx {
91 internal + 1
92}
93}
9495#[cfg(test)]
96mod tests {
97use super::*;
9899#[fuchsia::test]
100fn call_list_insert() {
101let mut list = List::default();
102let i1 = list.insert(1);
103assert_eq!(i1, 1, "The first value must be assigned the number 1");
104let i2 = list.insert(2);
105assert_eq!(i2, 2, "The second value is assigned the next available number");
106 }
107108#[fuchsia::test]
109fn call_list_get() {
110let mut list = List::default();
111let i1 = list.insert(1);
112let i2 = list.insert(2);
113assert_eq!(list.get(0), None);
114assert_eq!(list.get(i1), Some(&1));
115assert_eq!(list.get(i2), Some(&2));
116assert_eq!(list.get(3), None);
117 }
118119#[fuchsia::test]
120fn call_list_get_mut() {
121let mut list = List::default();
122let i1 = list.insert(1);
123let i2 = list.insert(2);
124assert_eq!(list.get_mut(i1), Some(&mut 1));
125assert_eq!(list.get_mut(i2), Some(&mut 2));
126assert_eq!(list.get_mut(3), None);
127 }
128129#[fuchsia::test]
130fn call_list_remove() {
131let mut list = List::default();
132let i1 = list.insert(1);
133let i2 = list.insert(2);
134let removed = list.remove(i1);
135assert!(removed.is_some());
136assert_eq!(list.get(i1), None, "The value at i1 is removed");
137assert_eq!(list.get(i2), Some(&2), "The value at i2 is untouched");
138let invalid_idx = 0;
139assert!(list.remove(invalid_idx).is_none());
140 }
141142#[fuchsia::test]
143fn call_list_remove_and_insert_behaves() {
144let mut list = List::default();
145let i1 = list.insert(1);
146let i2 = list.insert(2);
147let i3 = list.insert(3);
148let i4 = list.insert(4);
149assert!(list.remove(i2).is_some());
150assert!(list.remove(i1).is_some());
151assert!(list.remove(i3).is_some());
152let i5 = list.insert(5);
153assert_eq!(i5, i1, "i5 is the lowest possible index (i1) even though i1 was not the first or last index removed");
154assert_eq!(list.get(i5), Some(&5), "The value at i5 is correct");
155let i6 = list.insert(6);
156let i7 = list.insert(7);
157assert_eq!(i6, i2, "i6 takes the next available index (i2)");
158assert_eq!(i7, i3, "i7 takes the next available index (i3)");
159let i8_ = list.insert(8);
160assert_ne!(i8_, i4, "i4 is reserved, so i8_ must take a new index");
161assert_eq!(
162 i8_, 5,
163"i8_ takes an index of 5 since it is the last of the 5 values to be inserted"
164);
165 }
166167#[fuchsia::test]
168fn call_list_iter_returns_all_valid_values() {
169let mut list = List::default();
170let i1 = list.insert(1);
171let i2 = list.insert(2);
172let i3 = list.insert(3);
173let i4 = list.insert(4);
174assert!(list.remove(i2).is_some());
175let actual: Vec<_> = list.calls().collect();
176let expected = vec![(i1, &1), (i3, &3), (i4, &4)];
177assert_eq!(actual, expected);
178 }
179}