assembler.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. use core::fmt;
  2. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  3. pub struct TooManyHolesError;
  4. /// A contiguous chunk of absent data, followed by a contiguous chunk of present data.
  5. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  6. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  7. struct Contig {
  8. hole_size: usize,
  9. data_size: usize,
  10. }
  11. impl fmt::Display for Contig {
  12. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  13. if self.has_hole() {
  14. write!(f, "({})", self.hole_size)?;
  15. }
  16. if self.has_hole() && self.has_data() {
  17. write!(f, " ")?;
  18. }
  19. if self.has_data() {
  20. write!(f, "{}", self.data_size)?;
  21. }
  22. Ok(())
  23. }
  24. }
  25. impl Contig {
  26. fn empty() -> Contig {
  27. Contig {
  28. hole_size: 0,
  29. data_size: 0,
  30. }
  31. }
  32. fn hole(size: usize) -> Contig {
  33. Contig {
  34. hole_size: size,
  35. data_size: 0,
  36. }
  37. }
  38. fn hole_and_data(hole_size: usize, data_size: usize) -> Contig {
  39. Contig {
  40. hole_size,
  41. data_size,
  42. }
  43. }
  44. fn has_hole(&self) -> bool {
  45. self.hole_size != 0
  46. }
  47. fn has_data(&self) -> bool {
  48. self.data_size != 0
  49. }
  50. fn total_size(&self) -> usize {
  51. self.hole_size + self.data_size
  52. }
  53. fn is_empty(&self) -> bool {
  54. self.total_size() == 0
  55. }
  56. fn expand_data_by(&mut self, size: usize) {
  57. self.data_size += size;
  58. }
  59. fn shrink_hole_by(&mut self, size: usize) {
  60. self.hole_size -= size;
  61. }
  62. fn shrink_hole_to(&mut self, size: usize) {
  63. debug_assert!(self.hole_size >= size);
  64. let total_size = self.total_size();
  65. self.hole_size = size;
  66. self.data_size = total_size - size;
  67. }
  68. }
  69. #[cfg(feature = "alloc")]
  70. use alloc::boxed::Box;
  71. #[cfg(feature = "alloc")]
  72. const CONTIG_COUNT: usize = 32;
  73. #[cfg(not(feature = "alloc"))]
  74. const CONTIG_COUNT: usize = 4;
  75. /// A buffer (re)assembler.
  76. ///
  77. /// Currently, up to a hardcoded limit of 4 or 32 holes can be tracked in the buffer.
  78. #[derive(Debug, PartialEq, Eq, Clone)]
  79. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  80. pub struct Assembler {
  81. #[cfg(not(feature = "alloc"))]
  82. contigs: [Contig; CONTIG_COUNT],
  83. #[cfg(feature = "alloc")]
  84. contigs: Box<[Contig; CONTIG_COUNT]>,
  85. }
  86. impl fmt::Display for Assembler {
  87. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  88. write!(f, "[ ")?;
  89. for contig in self.contigs.iter() {
  90. if contig.is_empty() {
  91. break;
  92. }
  93. write!(f, "{} ", contig)?;
  94. }
  95. write!(f, "]")?;
  96. Ok(())
  97. }
  98. }
  99. impl Assembler {
  100. /// Create a new buffer assembler for buffers of the given size.
  101. pub fn new(size: usize) -> Assembler {
  102. #[cfg(not(feature = "alloc"))]
  103. let mut contigs = [Contig::empty(); CONTIG_COUNT];
  104. #[cfg(feature = "alloc")]
  105. let mut contigs = Box::new([Contig::empty(); CONTIG_COUNT]);
  106. contigs[0] = Contig::hole(size);
  107. Assembler { contigs }
  108. }
  109. /// FIXME(whitequark): remove this once I'm certain enough that the assembler works well.
  110. #[allow(dead_code)]
  111. pub(crate) fn total_size(&self) -> usize {
  112. self.contigs.iter().map(|contig| contig.total_size()).sum()
  113. }
  114. fn front(&self) -> Contig {
  115. self.contigs[0]
  116. }
  117. /// Return length of the front contiguous range without removing it from the assembler
  118. pub fn peek_front(&self) -> Option<usize> {
  119. let front = self.front();
  120. if front.has_hole() {
  121. None
  122. } else {
  123. Some(front.data_size)
  124. }
  125. }
  126. fn back(&self) -> Contig {
  127. self.contigs[self.contigs.len() - 1]
  128. }
  129. /// Return whether the assembler contains no data.
  130. pub fn is_empty(&self) -> bool {
  131. !self.front().has_data()
  132. }
  133. /// Remove a contig at the given index, and return a pointer to the first contig
  134. /// without data.
  135. fn remove_contig_at(&mut self, at: usize) -> &mut Contig {
  136. debug_assert!(!self.contigs[at].is_empty());
  137. for i in at..self.contigs.len() - 1 {
  138. self.contigs[i] = self.contigs[i + 1];
  139. if !self.contigs[i].has_data() {
  140. self.contigs[i + 1] = Contig::empty();
  141. return &mut self.contigs[i];
  142. }
  143. }
  144. // Removing the last one.
  145. let p = &mut self.contigs[self.contigs.len() - 1];
  146. *p = Contig::empty();
  147. p
  148. }
  149. /// Add a contig at the given index, and return a pointer to it.
  150. fn add_contig_at(&mut self, at: usize) -> Result<&mut Contig, TooManyHolesError> {
  151. debug_assert!(!self.contigs[at].is_empty());
  152. if !self.back().is_empty() {
  153. return Err(TooManyHolesError);
  154. }
  155. for i in (at + 1..self.contigs.len()).rev() {
  156. self.contigs[i] = self.contigs[i - 1];
  157. }
  158. self.contigs[at] = Contig::empty();
  159. Ok(&mut self.contigs[at])
  160. }
  161. /// Add a new contiguous range to the assembler, and return `Ok(bool)`,
  162. /// or return `Err(TooManyHolesError)` if too many discontiguities are already recorded.
  163. pub fn add(&mut self, mut offset: usize, mut size: usize) -> Result<(), TooManyHolesError> {
  164. let mut index = 0;
  165. while index != self.contigs.len() && size != 0 {
  166. let contig = self.contigs[index];
  167. if offset >= contig.total_size() {
  168. // The range being added does not cover this contig, skip it.
  169. index += 1;
  170. } else if offset == 0 && size >= contig.hole_size && index > 0 {
  171. // The range being added covers the entire hole in this contig, merge it
  172. // into the previous config.
  173. self.contigs[index - 1].expand_data_by(contig.total_size());
  174. self.remove_contig_at(index);
  175. index += 0;
  176. } else if offset == 0 && size < contig.hole_size && index > 0 {
  177. // The range being added covers a part of the hole in this contig starting
  178. // at the beginning, shrink the hole in this contig and expand data in
  179. // the previous contig.
  180. self.contigs[index - 1].expand_data_by(size);
  181. self.contigs[index].shrink_hole_by(size);
  182. index += 1;
  183. } else if offset <= contig.hole_size && offset + size >= contig.hole_size {
  184. // The range being added covers both a part of the hole and a part of the data
  185. // in this contig, shrink the hole in this contig.
  186. self.contigs[index].shrink_hole_to(offset);
  187. index += 1;
  188. } else if offset + size >= contig.hole_size {
  189. // The range being added covers only a part of the data in this contig, skip it.
  190. index += 1;
  191. } else if offset + size < contig.hole_size {
  192. // The range being added covers a part of the hole but not of the data
  193. // in this contig, add a new contig containing the range.
  194. {
  195. let inserted = self.add_contig_at(index)?;
  196. *inserted = Contig::hole_and_data(offset, size);
  197. }
  198. // Previous contigs[index] got moved to contigs[index+1]
  199. self.contigs[index + 1].shrink_hole_by(offset + size);
  200. index += 2;
  201. } else {
  202. unreachable!()
  203. }
  204. // Skip the portion of the range covered by this contig.
  205. if offset >= contig.total_size() {
  206. offset = offset.saturating_sub(contig.total_size());
  207. } else {
  208. size = (offset + size).saturating_sub(contig.total_size());
  209. offset = 0;
  210. }
  211. }
  212. debug_assert!(size == 0);
  213. Ok(())
  214. }
  215. /// Remove a contiguous range from the front of the assembler and `Some(data_size)`,
  216. /// or return `None` if there is no such range.
  217. pub fn remove_front(&mut self) -> Option<usize> {
  218. let front = self.front();
  219. if front.has_hole() {
  220. None
  221. } else {
  222. let last_hole = self.remove_contig_at(0);
  223. last_hole.hole_size += front.data_size;
  224. debug_assert!(front.data_size > 0);
  225. Some(front.data_size)
  226. }
  227. }
  228. /// Iterate over all of the contiguous data ranges.
  229. ///
  230. /// This is used in calculating what data ranges have been received. The offset indicates the
  231. /// number of bytes of contiguous data received before the beginnings of this Assembler.
  232. ///
  233. /// Data Hole Data
  234. /// |--- 100 ---|--- 200 ---|--- 100 ---|
  235. ///
  236. /// An offset of 1500 would return the ranges: ``(1500, 1600), (1800, 1900)``
  237. pub fn iter_data(&self, first_offset: usize) -> AssemblerIter {
  238. AssemblerIter::new(self, first_offset)
  239. }
  240. }
  241. pub struct AssemblerIter<'a> {
  242. assembler: &'a Assembler,
  243. offset: usize,
  244. index: usize,
  245. left: usize,
  246. right: usize,
  247. }
  248. impl<'a> AssemblerIter<'a> {
  249. fn new(assembler: &'a Assembler, offset: usize) -> AssemblerIter<'a> {
  250. AssemblerIter {
  251. assembler,
  252. offset,
  253. index: 0,
  254. left: 0,
  255. right: 0,
  256. }
  257. }
  258. }
  259. impl<'a> Iterator for AssemblerIter<'a> {
  260. type Item = (usize, usize);
  261. fn next(&mut self) -> Option<(usize, usize)> {
  262. let mut data_range = None;
  263. while data_range.is_none() && self.index < self.assembler.contigs.len() {
  264. let contig = self.assembler.contigs[self.index];
  265. self.left += contig.hole_size;
  266. self.right = self.left + contig.data_size;
  267. data_range = if self.left < self.right {
  268. let data_range = (self.left + self.offset, self.right + self.offset);
  269. self.left = self.right;
  270. Some(data_range)
  271. } else {
  272. None
  273. };
  274. self.index += 1;
  275. }
  276. data_range
  277. }
  278. }
  279. #[cfg(test)]
  280. mod test {
  281. use super::*;
  282. use std::vec::Vec;
  283. impl From<Vec<(usize, usize)>> for Assembler {
  284. fn from(vec: Vec<(usize, usize)>) -> Assembler {
  285. #[cfg(not(feature = "alloc"))]
  286. let mut contigs = [Contig::empty(); CONTIG_COUNT];
  287. #[cfg(feature = "alloc")]
  288. let mut contigs = Box::new([Contig::empty(); CONTIG_COUNT]);
  289. for (i, &(hole_size, data_size)) in vec.iter().enumerate() {
  290. contigs[i] = Contig {
  291. hole_size,
  292. data_size,
  293. };
  294. }
  295. Assembler { contigs }
  296. }
  297. }
  298. macro_rules! contigs {
  299. [$( $x:expr ),*] => ({
  300. Assembler::from(vec![$( $x ),*])
  301. })
  302. }
  303. #[test]
  304. fn test_new() {
  305. let assr = Assembler::new(16);
  306. assert_eq!(assr.total_size(), 16);
  307. assert_eq!(assr, contigs![(16, 0)]);
  308. }
  309. #[test]
  310. fn test_empty_add_full() {
  311. let mut assr = Assembler::new(16);
  312. assert_eq!(assr.add(0, 16), Ok(()));
  313. assert_eq!(assr, contigs![(0, 16)]);
  314. }
  315. #[test]
  316. fn test_empty_add_front() {
  317. let mut assr = Assembler::new(16);
  318. assert_eq!(assr.add(0, 4), Ok(()));
  319. assert_eq!(assr, contigs![(0, 4), (12, 0)]);
  320. }
  321. #[test]
  322. fn test_empty_add_back() {
  323. let mut assr = Assembler::new(16);
  324. assert_eq!(assr.add(12, 4), Ok(()));
  325. assert_eq!(assr, contigs![(12, 4)]);
  326. }
  327. #[test]
  328. fn test_empty_add_mid() {
  329. let mut assr = Assembler::new(16);
  330. assert_eq!(assr.add(4, 8), Ok(()));
  331. assert_eq!(assr, contigs![(4, 8), (4, 0)]);
  332. }
  333. #[test]
  334. fn test_partial_add_front() {
  335. let mut assr = contigs![(4, 8), (4, 0)];
  336. assert_eq!(assr.add(0, 4), Ok(()));
  337. assert_eq!(assr, contigs![(0, 12), (4, 0)]);
  338. }
  339. #[test]
  340. fn test_partial_add_back() {
  341. let mut assr = contigs![(4, 8), (4, 0)];
  342. assert_eq!(assr.add(12, 4), Ok(()));
  343. assert_eq!(assr, contigs![(4, 12)]);
  344. }
  345. #[test]
  346. fn test_partial_add_front_overlap() {
  347. let mut assr = contigs![(4, 8), (4, 0)];
  348. assert_eq!(assr.add(0, 8), Ok(()));
  349. assert_eq!(assr, contigs![(0, 12), (4, 0)]);
  350. }
  351. #[test]
  352. fn test_partial_add_front_overlap_split() {
  353. let mut assr = contigs![(4, 8), (4, 0)];
  354. assert_eq!(assr.add(2, 6), Ok(()));
  355. assert_eq!(assr, contigs![(2, 10), (4, 0)]);
  356. }
  357. #[test]
  358. fn test_partial_add_back_overlap() {
  359. let mut assr = contigs![(4, 8), (4, 0)];
  360. assert_eq!(assr.add(8, 8), Ok(()));
  361. assert_eq!(assr, contigs![(4, 12)]);
  362. }
  363. #[test]
  364. fn test_partial_add_back_overlap_split() {
  365. let mut assr = contigs![(4, 8), (4, 0)];
  366. assert_eq!(assr.add(10, 4), Ok(()));
  367. assert_eq!(assr, contigs![(4, 10), (2, 0)]);
  368. }
  369. #[test]
  370. fn test_partial_add_both_overlap() {
  371. let mut assr = contigs![(4, 8), (4, 0)];
  372. assert_eq!(assr.add(0, 16), Ok(()));
  373. assert_eq!(assr, contigs![(0, 16)]);
  374. }
  375. #[test]
  376. fn test_partial_add_both_overlap_split() {
  377. let mut assr = contigs![(4, 8), (4, 0)];
  378. assert_eq!(assr.add(2, 12), Ok(()));
  379. assert_eq!(assr, contigs![(2, 12), (2, 0)]);
  380. }
  381. #[test]
  382. fn test_rejected_add_keeps_state() {
  383. let mut assr = Assembler::new(CONTIG_COUNT * 20);
  384. for c in 1..=CONTIG_COUNT - 1 {
  385. assert_eq!(assr.add(c * 10, 3), Ok(()));
  386. }
  387. // Maximum of allowed holes is reached
  388. let assr_before = assr.clone();
  389. assert_eq!(assr.add(1, 3), Err(TooManyHolesError));
  390. assert_eq!(assr_before, assr);
  391. }
  392. #[test]
  393. fn test_empty_remove_front() {
  394. let mut assr = contigs![(12, 0)];
  395. assert_eq!(assr.remove_front(), None);
  396. }
  397. #[test]
  398. fn test_trailing_hole_remove_front() {
  399. let mut assr = contigs![(0, 4), (8, 0)];
  400. assert_eq!(assr.remove_front(), Some(4));
  401. assert_eq!(assr, contigs![(12, 0)]);
  402. }
  403. #[test]
  404. fn test_trailing_data_remove_front() {
  405. let mut assr = contigs![(0, 4), (4, 4)];
  406. assert_eq!(assr.remove_front(), Some(4));
  407. assert_eq!(assr, contigs![(4, 4), (4, 0)]);
  408. }
  409. #[test]
  410. fn test_boundary_case_remove_front() {
  411. let mut vec = vec![(1, 1); CONTIG_COUNT];
  412. vec[0] = (0, 2);
  413. let mut assr = Assembler::from(vec);
  414. assert_eq!(assr.remove_front(), Some(2));
  415. let mut vec = vec![(1, 1); CONTIG_COUNT];
  416. vec[CONTIG_COUNT - 1] = (2, 0);
  417. let exp_assr = Assembler::from(vec);
  418. assert_eq!(assr, exp_assr);
  419. }
  420. #[test]
  421. fn test_iter_empty() {
  422. let assr = Assembler::new(16);
  423. let segments: Vec<_> = assr.iter_data(10).collect();
  424. assert_eq!(segments, vec![]);
  425. }
  426. #[test]
  427. fn test_iter_full() {
  428. let mut assr = Assembler::new(16);
  429. assert_eq!(assr.add(0, 16), Ok(()));
  430. let segments: Vec<_> = assr.iter_data(10).collect();
  431. assert_eq!(segments, vec![(10, 26)]);
  432. }
  433. #[test]
  434. fn test_iter_offset() {
  435. let mut assr = Assembler::new(16);
  436. assert_eq!(assr.add(0, 16), Ok(()));
  437. let segments: Vec<_> = assr.iter_data(100).collect();
  438. assert_eq!(segments, vec![(100, 116)]);
  439. }
  440. #[test]
  441. fn test_iter_one_front() {
  442. let mut assr = Assembler::new(16);
  443. assert_eq!(assr.add(0, 4), Ok(()));
  444. let segments: Vec<_> = assr.iter_data(10).collect();
  445. assert_eq!(segments, vec![(10, 14)]);
  446. }
  447. #[test]
  448. fn test_iter_one_back() {
  449. let mut assr = Assembler::new(16);
  450. assert_eq!(assr.add(12, 4), Ok(()));
  451. let segments: Vec<_> = assr.iter_data(10).collect();
  452. assert_eq!(segments, vec![(22, 26)]);
  453. }
  454. #[test]
  455. fn test_iter_one_mid() {
  456. let mut assr = Assembler::new(16);
  457. assert_eq!(assr.add(4, 8), Ok(()));
  458. let segments: Vec<_> = assr.iter_data(10).collect();
  459. assert_eq!(segments, vec![(14, 22)]);
  460. }
  461. #[test]
  462. fn test_iter_one_trailing_gap() {
  463. let assr = contigs![(4, 8), (4, 0)];
  464. let segments: Vec<_> = assr.iter_data(100).collect();
  465. assert_eq!(segments, vec![(104, 112)]);
  466. }
  467. #[test]
  468. fn test_iter_two_split() {
  469. let assr = contigs![(2, 6), (4, 1), (1, 0)];
  470. let segments: Vec<_> = assr.iter_data(100).collect();
  471. assert_eq!(segments, vec![(102, 108), (112, 113)]);
  472. }
  473. #[test]
  474. fn test_iter_three_split() {
  475. let assr = contigs![(2, 6), (2, 1), (2, 2), (1, 0)];
  476. let segments: Vec<_> = assr.iter_data(100).collect();
  477. assert_eq!(segments, vec![(102, 108), (110, 111), (113, 115)]);
  478. }
  479. #[test]
  480. fn test_issue_694() {
  481. let mut assr = Assembler::new(16);
  482. assert_eq!(assr.add(0, 1), Ok(()));
  483. assert_eq!(assr.add(2, 1), Ok(()));
  484. assert_eq!(assr.add(1, 1), Ok(()));
  485. }
  486. }