forc_pkg/source/reg/
file_location.rs1use serde::{Deserialize, Serialize};
2use std::{fmt::Display, path::PathBuf};
3
4const NESTING_LEVELS: usize = 2;
6
7#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
8pub enum Namespace {
9 Flat,
13 Domain(String),
18}
19
20impl Display for Namespace {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 match self {
23 Namespace::Flat => write!(f, ""),
24 Namespace::Domain(s) => write!(f, "{s}"),
25 }
26 }
27}
28
29pub fn location_from_root(chunk_size: usize, namespace: &Namespace, package_name: &str) -> PathBuf {
33 let mut path = PathBuf::new();
34
35 match namespace {
38 Namespace::Domain(domain) if !domain.is_empty() => {
39 path.push(domain);
40 }
41 _ => {}
42 }
43
44 if chunk_size == 0 {
46 path.push(package_name);
47 return path;
48 }
49
50 let char_count = chunk_size * NESTING_LEVELS;
51 let to_be_chunked_section = package_name
52 .chars()
53 .enumerate()
54 .take_while(|(index, _)| *index < char_count)
55 .map(|(_, ch)| ch);
56
57 let chars: Vec<char> = to_be_chunked_section.collect();
58 for chunk in chars.chunks(chunk_size) {
59 let chunk_str: String = chunk.iter().collect();
60 path.push(chunk_str);
61 }
62
63 path.push(package_name);
64 path
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use crate::source::reg::index_file::PackageEntry;
71 use semver::Version;
72 use std::path::Path;
73
74 fn create_package_entry(name: &str) -> PackageEntry {
75 let name = name.to_string();
76 let version = Version::new(1, 0, 0);
77 let source_cid = "QmHash".to_string();
78 let abi_cid = None;
79 let dependencies = vec![];
80 let yanked = false;
81 PackageEntry::new(name, version, source_cid, abi_cid, dependencies, yanked)
82 }
83
84 #[test]
85 fn test_flat_namespace_with_small_package() {
86 let chunk_size = 2;
87 let namespace = Namespace::Flat;
88 let entry = create_package_entry("ab");
89
90 let path = location_from_root(chunk_size, &namespace, entry.name());
91
92 assert_eq!(path, Path::new("ab").join("ab"));
93 }
94
95 #[test]
96 fn test_flat_namespace_with_regular_package() {
97 let chunk_size = 2;
98 let namespace = Namespace::Flat;
99 let entry = create_package_entry("foobar");
100
101 let path = location_from_root(chunk_size, &namespace, entry.name());
102
103 assert_eq!(path, Path::new("fo").join("ob").join("foobar"));
105 }
106
107 #[test]
108 fn test_domain_namespace() {
109 let chunk_size = 2;
110 let namespace = Namespace::Domain("example".to_string());
111 let entry = create_package_entry("foobar");
112
113 let path = location_from_root(chunk_size, &namespace, entry.name());
114
115 assert_eq!(
117 path,
118 Path::new("example").join("fo").join("ob").join("foobar")
119 );
120 }
121
122 #[test]
123 fn test_odd_length_package_name() {
124 let chunk_size = 2;
125 let namespace = Namespace::Flat;
126 let entry = create_package_entry("hello");
127
128 let path = location_from_root(chunk_size, &namespace, entry.name());
129
130 assert_eq!(path, Path::new("he").join("ll").join("hello"));
132 }
133
134 #[test]
135 fn test_larger_chunking_size() {
136 let chunk_size = 3;
137 let namespace = Namespace::Flat;
138 let entry = create_package_entry("fibonacci");
139
140 let path = location_from_root(chunk_size, &namespace, entry.name());
141
142 assert_eq!(path, Path::new("fib").join("ona").join("fibonacci"));
144 }
145
146 #[test]
147 fn test_chunking_size_larger_than_name() {
148 let chunk_size = 10;
149 let namespace = Namespace::Flat;
150 let entry = create_package_entry("small");
151
152 let path = location_from_root(chunk_size, &namespace, entry.name());
153
154 assert_eq!(path, Path::new("small").join("small"));
156 }
157
158 #[test]
159 fn test_unicode_package_name() {
160 let chunk_size = 2;
161 let namespace = Namespace::Flat;
162 let entry = create_package_entry("héllo");
163
164 let path = location_from_root(chunk_size, &namespace, entry.name());
165
166 assert_eq!(path, Path::new("hé").join("ll").join("héllo"));
168 }
169
170 #[test]
171 fn test_empty_package_name() {
172 let chunk_size = 0;
173 let namespace = Namespace::Flat;
174 let entry = create_package_entry("");
175
176 let path = location_from_root(chunk_size, &namespace, entry.name());
177
178 assert_eq!(path, Path::new(""));
180 }
181
182 #[test]
183 fn test_chunking_size_zero() {
184 let chunk_size = 0;
185 let namespace = Namespace::Flat;
186 let entry = create_package_entry("package");
187
188 let path = location_from_root(chunk_size, &namespace, entry.name());
189
190 assert_eq!(path, Path::new("package"));
192 }
193}