block_path.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. pub use private::{BlockPath, BlockPathError};
  2. mod private {
  3. use crate::{crypto::Hash, Principal};
  4. use serde::{Deserialize, Serialize};
  5. use std::fmt::Display;
  6. /// An identifier for a block in a tree.
  7. #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Default)]
  8. pub struct BlockPath {
  9. root: Principal,
  10. components: Vec<String>,
  11. }
  12. impl BlockPath {
  13. /// The character that is used to separate path components.
  14. const SEP: char = '/';
  15. /// The limit, in bytes, of a path's length.
  16. const BYTE_LIMIT: usize = 4096;
  17. pub fn new(root: Principal, components: Vec<String>) -> BlockPath {
  18. BlockPath { root, components }
  19. }
  20. /// Returns a result which, when successful, contains the index after the last character in
  21. /// the current path component.
  22. fn component_end<I: Iterator<Item = (usize, char)>>(
  23. start: usize,
  24. first: char,
  25. pairs: &mut I,
  26. ) -> std::result::Result<usize, BlockPathError> {
  27. if first == BlockPath::SEP {
  28. return Err(BlockPathError::EmptyComponent);
  29. }
  30. let end;
  31. let mut last = start;
  32. loop {
  33. match pairs.next() {
  34. Some((index, BlockPath::SEP)) => {
  35. end = index;
  36. break;
  37. }
  38. Some((index, _)) => last = index,
  39. None => {
  40. end = last + 1;
  41. break;
  42. }
  43. }
  44. }
  45. if end == start {
  46. Err(BlockPathError::EmptyComponent)
  47. } else {
  48. Ok(end)
  49. }
  50. }
  51. /// Asserts that the number of bytes in the given string is no more than `Path::BYTE_LIMIT`.
  52. fn assert_not_too_long(string: &str) -> std::result::Result<(), BlockPathError> {
  53. let len = string.len();
  54. if len > BlockPath::BYTE_LIMIT {
  55. return Err(BlockPathError::PathTooLong(len));
  56. }
  57. Ok(())
  58. }
  59. /// Returns true if `other` is a subpath of this `Path`.
  60. pub fn contains(&self, other: &BlockPath) -> bool {
  61. if self.root != other.root {
  62. return false;
  63. };
  64. // This path must be no longer than the other path.
  65. if self.components.len() > other.components.len() {
  66. return false;
  67. }
  68. // Skip the component containing the owner.
  69. let self_iter = self.components.iter().skip(1);
  70. let other_iter = other.components.iter().skip(1);
  71. for pair in self_iter.zip(other_iter) {
  72. if pair.0 != pair.1 {
  73. return false;
  74. }
  75. }
  76. true
  77. }
  78. pub fn root(&self) -> &Principal {
  79. &self.root
  80. }
  81. pub fn mut_root(&mut self) -> &mut Principal {
  82. &mut self.root
  83. }
  84. pub fn components(&self) -> impl Iterator<Item = &str> {
  85. self.components.iter().map(|e| e.as_str())
  86. }
  87. pub fn mut_components(&mut self) -> impl Iterator<Item = &mut String> {
  88. self.components.iter_mut()
  89. }
  90. pub fn push_component(&mut self, component: String) {
  91. self.components.push(component)
  92. }
  93. pub fn pop_component(&mut self) -> Option<String> {
  94. self.components.pop()
  95. }
  96. }
  97. impl<'s> TryFrom<&'s str> for BlockPath {
  98. type Error = BlockPathError;
  99. fn try_from(string: &'s str) -> std::result::Result<BlockPath, BlockPathError> {
  100. BlockPath::assert_not_too_long(string)?;
  101. let mut pairs = string.char_indices();
  102. let mut components = Vec::new();
  103. let mut last_end = 0;
  104. while let Some((start, c)) = pairs.next() {
  105. let end = BlockPath::component_end(start, c, &mut pairs)?;
  106. last_end = end;
  107. let slice = &string[start..end];
  108. components.push(slice.to_string());
  109. }
  110. // An empty component is added to the end to indicate if there was a trailing slash.
  111. if string.len() - 1 == last_end {
  112. components.push("".to_string());
  113. }
  114. let leading = components
  115. .get(0)
  116. .ok_or(BlockPathError::InvalidLeadingComponent)?;
  117. let hash = Hash::try_from(leading.as_str())
  118. .map_err(|_| BlockPathError::InvalidLeadingComponent)?;
  119. Ok(BlockPath {
  120. root: Principal(hash),
  121. components,
  122. })
  123. }
  124. }
  125. impl Display for BlockPath {
  126. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  127. if self.components.is_empty() {
  128. return write!(f, "");
  129. };
  130. let mut iter = self.components.iter();
  131. let first = iter.next().unwrap();
  132. let mut output = write!(f, "{}", first);
  133. for component in iter {
  134. output = write!(f, "{}{}", BlockPath::SEP, component)
  135. }
  136. output
  137. }
  138. }
  139. /// Errors which can occur when converting a string to a `Path`.
  140. #[derive(Debug, PartialEq, Eq)]
  141. pub enum BlockPathError {
  142. /// Occurs when the number of bytes in a string is greater than `Path::BYTE_LIMIT`.
  143. PathTooLong(usize),
  144. /// Indicates that a path string was empty.
  145. Empty,
  146. /// Occurs when a component in a path string was empty.
  147. EmptyComponent,
  148. /// Occurs when the leading component of a path is not in the correct format.
  149. InvalidLeadingComponent,
  150. }
  151. impl Display for BlockPathError {
  152. fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  153. match self {
  154. BlockPathError::PathTooLong(length) => formatter.write_fmt(format_args!(
  155. "path contained {} bytes, which is over the {} byte limit",
  156. length,
  157. BlockPath::BYTE_LIMIT
  158. )),
  159. BlockPathError::Empty => formatter.write_str("path was empty"),
  160. BlockPathError::EmptyComponent => {
  161. formatter.write_str("component of path was empty")
  162. }
  163. BlockPathError::InvalidLeadingComponent => {
  164. formatter.write_str("invalid leading path component")
  165. }
  166. }
  167. }
  168. }
  169. }
  170. #[cfg(test)]
  171. mod tests {
  172. use crate::{
  173. crypto::Hash,
  174. test_helpers::{make_path, make_principal, PRINCIPAL2},
  175. Principal,
  176. };
  177. use super::*;
  178. fn path_from_str_test_case(
  179. expected: std::result::Result<BlockPath, BlockPathError>,
  180. input: &str,
  181. ) -> std::result::Result<(), BlockPathError> {
  182. let result = BlockPath::try_from(input);
  183. assert_eq!(expected, result);
  184. Ok(())
  185. }
  186. #[test]
  187. fn path_from_str_multiple_components_ok() -> std::result::Result<(), BlockPathError> {
  188. let expected = make_path(vec!["red", "green", "blue"]);
  189. let input = format!("{}/red/green/blue", expected.root());
  190. path_from_str_test_case(Ok(expected), input.as_str())?;
  191. Ok(())
  192. }
  193. #[test]
  194. fn path_from_str_one_component_ok() -> std::result::Result<(), BlockPathError> {
  195. let expected = make_path(vec![]);
  196. let input = expected.root().to_string();
  197. path_from_str_test_case(Ok(expected), input.as_str())?;
  198. Ok(())
  199. }
  200. #[test]
  201. fn path_from_str_trailing_slash_ok() -> std::result::Result<(), BlockPathError> {
  202. // Notice the empty component at the end of this path due to the trailing slash.
  203. let expected = make_path(vec!["orange", "banana", "shotgun", ""]);
  204. let input = format!("{}/orange/banana/shotgun/", expected.root());
  205. path_from_str_test_case(Ok(expected), input.as_str())?;
  206. Ok(())
  207. }
  208. #[test]
  209. fn path_from_str_path_too_long_fail() -> std::result::Result<(), BlockPathError> {
  210. let principal = make_principal();
  211. let input = format!("{}/{}", principal.0, "*".repeat(4097));
  212. let expected = Err(BlockPathError::PathTooLong(input.len()));
  213. path_from_str_test_case(expected, input.as_str())?;
  214. Ok(())
  215. }
  216. #[test]
  217. fn path_from_str_multiple_slashes_fail() -> std::result::Result<(), BlockPathError> {
  218. let expected = Err(BlockPathError::EmptyComponent);
  219. let input = format!("{}//orange", make_principal().0);
  220. path_from_str_test_case(expected, input.as_str())?;
  221. Ok(())
  222. }
  223. #[test]
  224. fn path_from_str_leading_slash_fail() -> std::result::Result<(), BlockPathError> {
  225. let expected = Err(BlockPathError::EmptyComponent);
  226. let input = format!("/{}/orange/banana/shotgun", make_principal().0);
  227. path_from_str_test_case(expected, input.as_str())?;
  228. Ok(())
  229. }
  230. #[test]
  231. fn path_round_trip() -> std::result::Result<(), BlockPathError> {
  232. let expected = make_path(vec!["interstitial", "inter-related", "intersections"]);
  233. let actual = BlockPath::try_from(expected.to_string().as_str())?;
  234. assert_eq!(expected, actual);
  235. Ok(())
  236. }
  237. #[test]
  238. fn path_contains_true() {
  239. let larger = make_path(vec!["apps"]);
  240. let smaller = make_path(vec!["apps", "bohdi"]);
  241. assert!(larger.contains(&smaller));
  242. }
  243. #[test]
  244. fn path_contains_true_only_owner() {
  245. let larger = make_path(vec![]);
  246. let smaller = make_path(vec![]);
  247. assert!(larger.contains(&smaller));
  248. }
  249. #[test]
  250. fn path_contains_false_self_is_longer() {
  251. let first = make_path(vec!["apps", "bohdi"]);
  252. let second = make_path(vec!["apps"]);
  253. assert!(!first.contains(&second));
  254. }
  255. #[test]
  256. fn path_contains_false_same_owners() {
  257. let first = make_path(vec!["apps"]);
  258. let second = make_path(vec!["nodes"]);
  259. assert!(!first.contains(&second));
  260. }
  261. #[test]
  262. fn path_contains_false_different_owners() {
  263. let first = make_path(vec!["apps"]);
  264. let mut second = make_path(vec!["apps"]);
  265. *second.mut_root() = Principal(Hash::Sha2_256(PRINCIPAL2));
  266. assert!(!first.contains(&second));
  267. }
  268. }