1use flyweights::FlyStr;
10use lazy_static::lazy_static;
11use serde::{de, ser, Deserialize, Serialize};
12use std::borrow::Borrow;
13use std::ffi::CString;
14use std::fmt::{self, Display};
15use std::ops::Deref;
16use std::path::PathBuf;
17use std::str::FromStr;
18use std::{cmp, iter};
19use thiserror::Error;
20use {fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_io as fio};
21
22lazy_static! {
23 static ref DEFAULT_BASE_URL: url::Url = url::Url::parse("relative:///").unwrap();
26}
27
28#[macro_export]
64macro_rules! symmetrical_enums {
65 ($a:ty , $b:ty, $($id: ident),*) => {
66 impl From<$a> for $b {
67 fn from(input: $a) -> Self {
68 match input {
69 $( <$a>::$id => <$b>::$id, )*
70 }
71 }
72 }
73
74 impl From<$b> for $a {
75 fn from(input: $b) -> Self {
76 match input {
77 $( <$b>::$id => <$a>::$id, )*
78 }
79 }
80 }
81 };
82}
83
84#[derive(Serialize, Clone, Deserialize, Debug, Error, PartialEq, Eq)]
86pub enum ParseError {
87 #[error("invalid value")]
89 InvalidValue,
90 #[error("invalid URL: {details}")]
92 InvalidComponentUrl { details: String },
93 #[error("empty")]
95 Empty,
96 #[error("too long")]
98 TooLong,
99 #[error("no leading slash")]
101 NoLeadingSlash,
102 #[error("invalid path segment")]
104 InvalidSegment,
105}
106
107pub const MAX_NAME_LENGTH: usize = name::MAX_NAME_LENGTH;
108pub const MAX_LONG_NAME_LENGTH: usize = 1024;
109pub const MAX_PATH_LENGTH: usize = fio::MAX_PATH_LENGTH as usize;
110pub const MAX_URL_LENGTH: usize = 4096;
111
112pub const FLAGS_MAX_POSSIBLE_RIGHTS: fio::Flags = fio::PERM_READABLE
116 .union(fio::Flags::PERM_INHERIT_WRITE)
117 .union(fio::Flags::PERM_INHERIT_EXECUTE);
118
119pub type Name = BoundedName<MAX_NAME_LENGTH>;
122pub type LongName = BoundedName<MAX_LONG_NAME_LENGTH>;
124
125#[derive(Serialize, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
127pub struct BoundedName<const N: usize>(FlyStr);
128
129impl Name {
130 #[inline]
131 pub fn to_long(self) -> LongName {
132 BoundedName(self.0)
133 }
134}
135
136impl<const N: usize> BoundedName<N> {
137 pub fn new(s: impl AsRef<str>) -> Result<Self, ParseError> {
143 let s = s.as_ref();
144 validate_name::<N>(s)?;
145 Ok(Self(FlyStr::new(s)))
146 }
147
148 fn new_unchecked<S: AsRef<str> + ?Sized>(s: &S) -> Self {
151 Self(FlyStr::new(s.as_ref()))
152 }
153
154 #[inline]
155 pub fn as_str(&self) -> &str {
156 &self.0
157 }
158
159 #[inline]
160 pub fn is_empty(&self) -> bool {
161 self.0.is_empty()
162 }
163
164 #[inline]
165 pub fn len(&self) -> usize {
166 self.0.len()
167 }
168}
169
170impl<const N: usize> AsRef<str> for BoundedName<N> {
171 #[inline]
172 fn as_ref(&self) -> &str {
173 self.as_str()
174 }
175}
176
177impl<const N: usize> AsRef<BoundedBorrowedName<N>> for BoundedName<N> {
178 #[inline]
179 fn as_ref(&self) -> &BoundedBorrowedName<N> {
180 BoundedBorrowedName::<N>::new_unchecked(self)
181 }
182}
183
184impl<const N: usize> AsRef<BoundedName<N>> for BoundedName<N> {
185 #[inline]
186 fn as_ref(&self) -> &BoundedName<N> {
187 self
188 }
189}
190
191impl<const N: usize> Borrow<FlyStr> for BoundedName<N> {
192 #[inline]
193 fn borrow(&self) -> &FlyStr {
194 &self.0
195 }
196}
197
198impl<const N: usize> Deref for BoundedName<N> {
199 type Target = BoundedBorrowedName<N>;
200
201 #[inline]
202 fn deref(&self) -> &BoundedBorrowedName<N> {
203 BoundedBorrowedName::new_unchecked(self.0.as_str())
204 }
205}
206
207impl<const N: usize> Borrow<BoundedBorrowedName<N>> for BoundedName<N> {
208 #[inline]
209 fn borrow(&self) -> &BoundedBorrowedName<N> {
210 self.deref()
211 }
212}
213
214impl<const N: usize> From<BoundedName<N>> for FlyStr {
215 #[inline]
216 fn from(o: BoundedName<N>) -> Self {
217 o.0
218 }
219}
220
221impl<'a, const N: usize> From<&'a BoundedName<N>> for &'a FlyStr {
222 #[inline]
223 fn from(o: &'a BoundedName<N>) -> Self {
224 &o.0
225 }
226}
227
228impl<const N: usize> PartialEq<&str> for BoundedName<N> {
229 #[inline]
230 fn eq(&self, o: &&str) -> bool {
231 &*self.0 == *o
232 }
233}
234
235impl<const N: usize> PartialEq<String> for BoundedName<N> {
236 #[inline]
237 fn eq(&self, o: &String) -> bool {
238 &*self.0 == *o
239 }
240}
241
242impl<const N: usize> fmt::Display for BoundedName<N> {
243 #[inline]
244 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245 <FlyStr as fmt::Display>::fmt(&self.0, f)
246 }
247}
248
249impl<const N: usize> FromStr for BoundedName<N> {
250 type Err = ParseError;
251
252 #[inline]
253 fn from_str(name: &str) -> Result<Self, Self::Err> {
254 Self::new(name)
255 }
256}
257
258impl<const N: usize> From<&BoundedBorrowedName<N>> for BoundedName<N> {
259 #[inline]
260 fn from(o: &BoundedBorrowedName<N>) -> Self {
261 Self(o.0.into())
262 }
263}
264
265impl<const N: usize> From<BoundedName<N>> for String {
266 #[inline]
267 fn from(name: BoundedName<N>) -> String {
268 name.0.into()
269 }
270}
271
272impl From<Name> for LongName {
273 #[inline]
274 fn from(name: Name) -> Self {
275 Self(name.0)
276 }
277}
278
279pub type BorrowedName = BoundedBorrowedName<MAX_NAME_LENGTH>;
281pub type BorrowedLongName = BoundedBorrowedName<MAX_LONG_NAME_LENGTH>;
283
284#[derive(Serialize, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
287#[repr(transparent)]
288pub struct BoundedBorrowedName<const N: usize>(str);
289
290impl BorrowedName {
291 #[inline]
292 pub fn to_long(&self) -> &BorrowedLongName {
293 unsafe { &*(self as *const BorrowedName as *const BorrowedLongName) }
297 }
298}
299
300impl<const N: usize> BoundedBorrowedName<N> {
301 pub fn new<S: AsRef<str> + ?Sized>(s: &S) -> Result<&Self, ParseError> {
304 validate_name::<N>(s.as_ref())?;
305 Ok(Self::new_unchecked(s))
306 }
307
308 fn new_unchecked<S: AsRef<str> + ?Sized>(s: &S) -> &Self {
311 unsafe { &*(s.as_ref() as *const str as *const Self) }
315 }
316
317 #[inline]
318 pub fn as_str(&self) -> &str {
319 &self.0
320 }
321
322 #[inline]
323 pub fn is_empty(&self) -> bool {
324 self.0.is_empty()
325 }
326
327 #[inline]
328 pub fn len(&self) -> usize {
329 self.0.len()
330 }
331}
332
333fn validate_name<const N: usize>(name: &str) -> Result<(), ParseError> {
334 if name.is_empty() {
335 return Err(ParseError::Empty);
336 }
337 if name.len() > N {
338 return Err(ParseError::TooLong);
339 }
340 let mut char_iter = name.chars();
341 let first_char = char_iter.next().unwrap();
342 if !first_char.is_ascii_alphanumeric() && first_char != '_' {
343 return Err(ParseError::InvalidValue);
344 }
345 let valid_fn = |c: char| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.';
346 if !char_iter.all(valid_fn) {
347 return Err(ParseError::InvalidValue);
348 }
349 Ok(())
350}
351
352impl<const N: usize> AsRef<str> for BoundedBorrowedName<N> {
353 #[inline]
354 fn as_ref(&self) -> &str {
355 &self.0
356 }
357}
358
359impl<const N: usize> Borrow<str> for BoundedBorrowedName<N> {
360 #[inline]
361 fn borrow(&self) -> &str {
362 &self.0
363 }
364}
365
366impl<const N: usize> Borrow<str> for &BoundedBorrowedName<N> {
367 #[inline]
368 fn borrow(&self) -> &str {
369 &self.0
370 }
371}
372
373impl<'a, const N: usize> From<&'a BoundedBorrowedName<N>> for &'a str {
374 #[inline]
375 fn from(o: &'a BoundedBorrowedName<N>) -> Self {
376 &o.0
377 }
378}
379
380impl<const N: usize> PartialEq<&str> for BoundedBorrowedName<N> {
381 #[inline]
382 fn eq(&self, o: &&str) -> bool {
383 &self.0 == *o
384 }
385}
386
387impl<const N: usize> PartialEq<String> for BoundedBorrowedName<N> {
388 #[inline]
389 fn eq(&self, o: &String) -> bool {
390 &self.0 == &*o
391 }
392}
393
394impl<const N: usize> fmt::Display for BoundedBorrowedName<N> {
395 #[inline]
396 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
397 <str as fmt::Display>::fmt(&self.0, f)
398 }
399}
400
401impl<'a> From<&'a BorrowedName> for &'a BorrowedLongName {
402 #[inline]
403 fn from(name: &'a BorrowedName) -> Self {
404 name.to_long()
405 }
406}
407
408impl<'de, const N: usize> de::Deserialize<'de> for BoundedName<N> {
409 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
410 where
411 D: de::Deserializer<'de>,
412 {
413 struct Visitor<const N: usize>;
414
415 impl<'de, const N: usize> de::Visitor<'de> for Visitor<N> {
416 type Value = BoundedName<{ N }>;
417
418 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419 f.write_str(&format!(
420 "a non-empty string no more than {} characters in length, \
421 consisting of [A-Za-z0-9_.-] and starting with [A-Za-z0-9_]",
422 N
423 ))
424 }
425
426 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
427 where
428 E: de::Error,
429 {
430 s.parse().map_err(|err| match err {
431 ParseError::InvalidValue => E::invalid_value(
432 de::Unexpected::Str(s),
433 &"a name that consists of [A-Za-z0-9_.-] and starts with [A-Za-z0-9_]",
434 ),
435 ParseError::TooLong | ParseError::Empty => E::invalid_length(
436 s.len(),
437 &format!("a non-empty name no more than {} characters in length", N)
438 .as_str(),
439 ),
440 e => {
441 panic!("unexpected parse error: {:?}", e);
442 }
443 })
444 }
445 }
446 deserializer.deserialize_string(Visitor)
447 }
448}
449
450impl IterablePath for Name {
451 fn iter_segments(&self) -> impl DoubleEndedIterator<Item = &BorrowedName> + Send {
452 iter::once(self as &BorrowedName)
453 }
454}
455
456impl IterablePath for &Name {
457 fn iter_segments(&self) -> impl DoubleEndedIterator<Item = &BorrowedName> + Send {
458 iter::once(*self as &BorrowedName)
459 }
460}
461
462#[derive(Eq, Ord, PartialOrd, PartialEq, Hash, Clone)]
467pub struct NamespacePath(RelativePath);
468
469impl NamespacePath {
470 pub fn new(path: impl AsRef<str>) -> Result<Self, ParseError> {
472 let path = path.as_ref();
473 if path.is_empty() {
474 return Err(ParseError::Empty);
475 }
476 if path == "." {
477 return Err(ParseError::InvalidValue);
478 }
479 if !path.starts_with('/') {
480 return Err(ParseError::NoLeadingSlash);
481 }
482 if path.len() > MAX_PATH_LENGTH {
483 return Err(ParseError::TooLong);
484 }
485 if path == "/" {
486 Ok(Self(RelativePath::dot()))
487 } else {
488 let path: RelativePath = path[1..].parse()?;
489 if path.is_dot() {
490 return Err(ParseError::InvalidSegment);
492 }
493 Ok(Self(path))
494 }
495 }
496
497 pub fn root() -> Self {
499 Self(RelativePath::dot())
500 }
501
502 pub fn is_root(&self) -> bool {
503 self.0.is_dot()
504 }
505
506 pub fn split(&self) -> Vec<&BorrowedName> {
508 self.0.split()
509 }
510
511 pub fn to_path_buf(&self) -> PathBuf {
512 PathBuf::from(self.to_string())
513 }
514
515 pub fn parent(&self) -> Option<Self> {
518 self.0.parent().map(|p| Self(p))
519 }
520
521 pub fn has_prefix(&self, prefix: &Self) -> bool {
529 let my_segments = self.split();
530 let prefix_segments = prefix.split();
531 prefix_segments.into_iter().zip(my_segments.into_iter()).all(|(a, b)| a == b)
532 }
533
534 pub fn basename(&self) -> Option<&BorrowedName> {
536 self.0.basename()
537 }
538
539 pub fn pop_front(&mut self) -> Option<Name> {
540 self.0.pop_front()
541 }
542}
543
544impl IterablePath for NamespacePath {
545 fn iter_segments(&self) -> impl DoubleEndedIterator<Item = &BorrowedName> + Send {
546 self.0.iter_segments()
547 }
548}
549
550impl serde::ser::Serialize for NamespacePath {
551 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
552 where
553 S: serde::ser::Serializer,
554 {
555 self.to_string().serialize(serializer)
556 }
557}
558
559impl TryFrom<CString> for NamespacePath {
560 type Error = ParseError;
561
562 fn try_from(path: CString) -> Result<Self, ParseError> {
563 Self::new(path.into_string().map_err(|_| ParseError::InvalidValue)?)
564 }
565}
566
567impl From<NamespacePath> for CString {
568 fn from(path: NamespacePath) -> Self {
569 unsafe { CString::from_vec_unchecked(path.to_string().as_bytes().to_owned()) }
572 }
573}
574
575impl From<NamespacePath> for String {
576 fn from(path: NamespacePath) -> Self {
577 path.to_string()
578 }
579}
580
581impl FromStr for NamespacePath {
582 type Err = ParseError;
583
584 fn from_str(path: &str) -> Result<Self, Self::Err> {
585 Self::new(path)
586 }
587}
588
589impl fmt::Debug for NamespacePath {
590 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
591 write!(f, "{}", self)
592 }
593}
594
595impl fmt::Display for NamespacePath {
596 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
597 if !self.0.is_dot() {
598 write!(f, "/{}", self.0)
599 } else {
600 write!(f, "/")
601 }
602 }
603}
604
605#[derive(Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
621pub struct Path(RelativePath);
622
623impl fmt::Debug for Path {
624 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
625 write!(f, "{}", self)
626 }
627}
628
629impl fmt::Display for Path {
630 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
631 write!(f, "/{}", self.0)
632 }
633}
634
635impl ser::Serialize for Path {
636 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
637 where
638 S: serde::ser::Serializer,
639 {
640 self.to_string().serialize(serializer)
641 }
642}
643
644impl Path {
645 pub fn new(path: impl AsRef<str>) -> Result<Self, ParseError> {
650 let path = path.as_ref();
651 if path.is_empty() {
652 return Err(ParseError::Empty);
653 }
654 if path == "/" || path == "." {
655 return Err(ParseError::InvalidValue);
656 }
657 if !path.starts_with('/') {
658 return Err(ParseError::NoLeadingSlash);
659 }
660 if path.len() > MAX_PATH_LENGTH {
661 return Err(ParseError::TooLong);
662 }
663 let path: RelativePath = path[1..].parse()?;
664 if path.is_dot() {
665 return Err(ParseError::InvalidSegment);
667 }
668 Ok(Self(path))
669 }
670
671 pub fn split(&self) -> Vec<&BorrowedName> {
673 self.0.split()
674 }
675
676 pub fn to_path_buf(&self) -> PathBuf {
677 PathBuf::from(self.to_string())
678 }
679
680 pub fn parent(&self) -> NamespacePath {
683 let p = self.0.parent().expect("can't be root");
684 NamespacePath(p)
685 }
686
687 pub fn basename(&self) -> &BorrowedName {
688 self.0.basename().expect("can't be root")
689 }
690
691 #[must_use]
694 pub fn extend(&mut self, other: RelativePath) -> bool {
695 let rep: FlyStr = if !other.is_dot() {
696 format!("{}/{}", self.0.rep, other.rep).into()
697 } else {
698 return true;
700 };
701 if rep.len() > MAX_PATH_LENGTH - 1 {
703 return false;
704 }
705 self.0.rep = rep;
706 true
707 }
708
709 #[must_use]
712 pub fn push(&mut self, segment: Name) -> bool {
713 let rep: FlyStr = format!("{}/{}", self.0.rep, segment).into();
714 if rep.len() > MAX_PATH_LENGTH - 1 {
716 return false;
717 }
718 self.0.rep = rep;
719 true
720 }
721}
722
723impl IterablePath for Path {
724 fn iter_segments(&self) -> impl DoubleEndedIterator<Item = &BorrowedName> + Send {
725 Box::new(self.0.iter_segments())
726 }
727}
728
729impl From<Path> for NamespacePath {
730 fn from(value: Path) -> Self {
731 Self(value.0)
732 }
733}
734
735impl FromStr for Path {
736 type Err = ParseError;
737
738 fn from_str(path: &str) -> Result<Self, Self::Err> {
739 Self::new(path)
740 }
741}
742
743impl TryFrom<CString> for Path {
744 type Error = ParseError;
745
746 fn try_from(path: CString) -> Result<Self, ParseError> {
747 Self::new(path.into_string().map_err(|_| ParseError::InvalidValue)?)
748 }
749}
750
751impl From<Path> for CString {
752 fn from(path: Path) -> Self {
753 unsafe { CString::from_vec_unchecked(path.to_string().as_bytes().to_owned()) }
756 }
757}
758
759impl From<Path> for String {
760 fn from(path: Path) -> String {
761 path.to_string()
762 }
763}
764
765impl<'de> de::Deserialize<'de> for Path {
766 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
767 where
768 D: de::Deserializer<'de>,
769 {
770 struct Visitor;
771
772 impl<'de> de::Visitor<'de> for Visitor {
773 type Value = Path;
774
775 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
776 f.write_str(
777 "a non-empty path no more than fuchsia.io/MAX_PATH_LENGTH characters \
778 in length, with a leading `/`, and containing no \
779 empty path segments",
780 )
781 }
782
783 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
784 where
785 E: de::Error,
786 {
787 s.parse().map_err(|err| {
788 match err {
789 ParseError::InvalidValue | ParseError::InvalidSegment | ParseError::NoLeadingSlash => E::invalid_value(
790 de::Unexpected::Str(s),
791 &"a path with leading `/` and non-empty segments, where each segment is no \
792 more than fuchsia.io/MAX_NAME_LENGTH bytes in length, cannot be . or .., \
793 and cannot contain embedded NULs",
794 ),
795 ParseError::TooLong | ParseError::Empty => E::invalid_length(
796 s.len(),
797 &"a non-empty path no more than fuchsia.io/MAX_PATH_LENGTH bytes \
798 in length",
799 ),
800 e => {
801 panic!("unexpected parse error: {:?}", e);
802 }
803 }
804 })
805 }
806 }
807 deserializer.deserialize_string(Visitor)
808 }
809}
810
811#[derive(Eq, Ord, PartialOrd, PartialEq, Hash, Clone)]
813pub struct RelativePath {
814 rep: FlyStr,
815}
816
817impl RelativePath {
818 pub fn new(path: impl AsRef<str>) -> Result<Self, ParseError> {
820 let path: &str = path.as_ref();
821 if path == "." {
822 return Ok(Self::dot());
823 }
824 if path.is_empty() {
825 return Err(ParseError::Empty);
826 }
827 if path.len() > MAX_PATH_LENGTH {
828 return Err(ParseError::TooLong);
829 }
830 path.split('/').try_for_each(|s| {
831 Name::new(s).map(|_| ()).map_err(|e| match e {
832 ParseError::Empty => ParseError::InvalidValue,
833 _ => ParseError::InvalidSegment,
834 })
835 })?;
836 Ok(Self { rep: path.into() })
837 }
838
839 pub fn dot() -> Self {
840 Self { rep: ".".into() }
841 }
842
843 pub fn is_dot(&self) -> bool {
844 self.rep == "."
845 }
846
847 pub fn parent(&self) -> Option<Self> {
848 if self.is_dot() {
849 None
850 } else {
851 match self.rep.rfind('/') {
852 Some(idx) => Some(Self::new(&self.rep[0..idx]).unwrap()),
853 None => Some(Self::dot()),
854 }
855 }
856 }
857
858 pub fn split(&self) -> Vec<&BorrowedName> {
859 if self.is_dot() {
860 vec![]
861 } else {
862 self.rep.split('/').map(|s| BorrowedName::new_unchecked(s)).collect()
863 }
864 }
865
866 pub fn basename(&self) -> Option<&BorrowedName> {
867 if self.is_dot() {
868 None
869 } else {
870 match self.rep.rfind('/') {
871 Some(idx) => Some(BorrowedName::new_unchecked(&self.rep[idx + 1..])),
872 None => Some(BorrowedName::new_unchecked(&self.rep)),
873 }
874 }
875 }
876
877 pub fn to_path_buf(&self) -> PathBuf {
878 if self.is_dot() {
879 PathBuf::new()
880 } else {
881 PathBuf::from(self.to_string())
882 }
883 }
884
885 #[must_use]
888 pub fn extend(&mut self, other: Self) -> bool {
889 let rep = if self.is_dot() {
890 other.rep
891 } else if !other.is_dot() {
892 format!("{}/{}", self.rep, other.rep).into()
893 } else {
894 return true;
896 };
897 if rep.len() > MAX_PATH_LENGTH {
898 return false;
899 }
900 self.rep = rep;
901 true
902 }
903
904 #[must_use]
907 pub fn push(&mut self, segment: Name) -> bool {
908 let rep: FlyStr = if self.is_dot() {
909 format!("{segment}").into()
910 } else {
911 format!("{}/{}", self.rep, segment).into()
912 };
913 if rep.len() > MAX_PATH_LENGTH {
914 return false;
915 }
916 self.rep = rep;
917 true
918 }
919
920 pub fn pop_front(&mut self) -> Option<Name> {
921 if self.is_dot() {
922 None
923 } else {
924 let (rep, front) = match self.rep.find('/') {
925 Some(idx) => {
926 let rep = self.rep[idx + 1..].into();
927 let front = Name::new_unchecked(&self.rep[0..idx]);
928 (rep, front)
929 }
930 None => (".".into(), Name::new_unchecked(&self.rep)),
931 };
932 self.rep = rep;
933 Some(front)
934 }
935 }
936}
937
938impl Default for RelativePath {
939 fn default() -> Self {
940 Self::dot()
941 }
942}
943
944impl IterablePath for RelativePath {
945 fn iter_segments(&self) -> impl DoubleEndedIterator<Item = &BorrowedName> + Send {
946 Box::new(self.split().into_iter())
947 }
948}
949
950impl FromStr for RelativePath {
951 type Err = ParseError;
952
953 fn from_str(path: &str) -> Result<Self, Self::Err> {
954 Self::new(path)
955 }
956}
957
958impl From<RelativePath> for String {
959 fn from(path: RelativePath) -> String {
960 path.to_string()
961 }
962}
963
964impl From<Vec<Name>> for RelativePath {
965 fn from(segments: Vec<Name>) -> Self {
966 if segments.is_empty() {
967 Self::dot()
968 } else {
969 Self { rep: segments.iter().map(|s| s.as_str()).collect::<Vec<_>>().join("/").into() }
970 }
971 }
972}
973
974impl From<Vec<&BorrowedName>> for RelativePath {
975 fn from(segments: Vec<&BorrowedName>) -> Self {
976 if segments.is_empty() {
977 Self::dot()
978 } else {
979 Self {
980 rep: segments.into_iter().map(|s| s.as_str()).collect::<Vec<_>>().join("/").into(),
981 }
982 }
983 }
984}
985
986impl fmt::Debug for RelativePath {
987 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
988 write!(f, "{}", self)
989 }
990}
991
992impl fmt::Display for RelativePath {
993 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
994 write!(f, "{}", self.rep)
995 }
996}
997
998impl ser::Serialize for RelativePath {
999 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1000 where
1001 S: serde::ser::Serializer,
1002 {
1003 self.to_string().serialize(serializer)
1004 }
1005}
1006
1007impl<'de> de::Deserialize<'de> for RelativePath {
1008 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1009 where
1010 D: de::Deserializer<'de>,
1011 {
1012 struct Visitor;
1013
1014 impl<'de> de::Visitor<'de> for Visitor {
1015 type Value = RelativePath;
1016
1017 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1018 f.write_str(
1019 "a non-empty path no more than fuchsia.io/MAX_PATH_LENGTH characters \
1020 in length, not starting with `/`, and containing no empty path segments",
1021 )
1022 }
1023
1024 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
1025 where
1026 E: de::Error,
1027 {
1028 s.parse().map_err(|err| match err {
1029 ParseError::InvalidValue
1030 | ParseError::InvalidSegment
1031 | ParseError::NoLeadingSlash => E::invalid_value(
1032 de::Unexpected::Str(s),
1033 &"a path with no leading `/` and non-empty segments",
1034 ),
1035 ParseError::TooLong | ParseError::Empty => E::invalid_length(
1036 s.len(),
1037 &"a non-empty path no more than fuchsia.io/MAX_PATH_LENGTH characters \
1038 in length",
1039 ),
1040 e => {
1041 panic!("unexpected parse error: {:?}", e);
1042 }
1043 })
1044 }
1045 }
1046 deserializer.deserialize_string(Visitor)
1047 }
1048}
1049
1050#[derive(Debug, Clone, PartialEq, Eq)]
1054pub struct BorrowedSeparatedPath<'a> {
1055 pub dirname: &'a RelativePath,
1056 pub basename: &'a Name,
1057}
1058
1059impl BorrowedSeparatedPath<'_> {
1060 pub fn to_owned(&self) -> SeparatedPath {
1062 SeparatedPath { dirname: self.dirname.clone(), basename: self.basename.clone() }
1063 }
1064}
1065
1066impl fmt::Display for BorrowedSeparatedPath<'_> {
1067 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1068 if !self.dirname.is_dot() {
1069 write!(f, "{}/{}", self.dirname, self.basename)
1070 } else {
1071 write!(f, "{}", self.basename)
1072 }
1073 }
1074}
1075
1076impl IterablePath for BorrowedSeparatedPath<'_> {
1077 fn iter_segments(&self) -> impl DoubleEndedIterator<Item = &BorrowedName> + Send {
1078 Box::new(self.dirname.iter_segments().chain(iter::once(self.basename as &BorrowedName)))
1079 }
1080}
1081
1082#[derive(Debug, Clone, PartialEq, Eq)]
1086pub struct SeparatedPath {
1087 pub dirname: RelativePath,
1088 pub basename: Name,
1089}
1090
1091impl SeparatedPath {
1092 pub fn as_ref(&self) -> BorrowedSeparatedPath<'_> {
1094 BorrowedSeparatedPath { dirname: &self.dirname, basename: &self.basename }
1095 }
1096}
1097
1098impl IterablePath for SeparatedPath {
1099 fn iter_segments(&self) -> impl DoubleEndedIterator<Item = &BorrowedName> + Send {
1100 Box::new(self.dirname.iter_segments().chain(iter::once(&self.basename as &BorrowedName)))
1101 }
1102}
1103
1104impl fmt::Display for SeparatedPath {
1105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1106 if !self.dirname.is_dot() {
1107 write!(f, "{}/{}", self.dirname, self.basename)
1108 } else {
1109 write!(f, "{}", self.basename)
1110 }
1111 }
1112}
1113
1114pub trait IterablePath: Clone + Send + Sync {
1116 fn iter_segments(&self) -> impl DoubleEndedIterator<Item = &BorrowedName> + Send;
1118}
1119
1120#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
1123pub struct Url(FlyStr);
1124
1125impl Url {
1126 pub fn new(url: impl AsRef<str> + Into<String>) -> Result<Self, ParseError> {
1130 Self::validate(url.as_ref())?;
1131 Ok(Self(FlyStr::new(url)))
1132 }
1133
1134 pub fn validate(url_str: &str) -> Result<(), ParseError> {
1136 if url_str.is_empty() {
1137 return Err(ParseError::Empty);
1138 }
1139 if url_str.len() > MAX_URL_LENGTH {
1140 return Err(ParseError::TooLong);
1141 }
1142 match url::Url::parse(url_str).map(|url| (url, false)).or_else(|err| {
1143 if err == url::ParseError::RelativeUrlWithoutBase {
1144 DEFAULT_BASE_URL.join(url_str).map(|url| (url, true))
1145 } else {
1146 Err(err)
1147 }
1148 }) {
1149 Ok((url, is_relative)) => {
1150 let mut path = url.path();
1151 if path.starts_with('/') {
1152 path = &path[1..];
1153 }
1154 if is_relative && url.fragment().is_none() {
1155 return Err(ParseError::InvalidComponentUrl {
1167 details: "Relative URL has no resource fragment.".to_string(),
1168 });
1169 }
1170 if url.host_str().unwrap_or("").is_empty()
1171 && path.is_empty()
1172 && url.fragment().is_none()
1173 {
1174 return Err(ParseError::InvalidComponentUrl {
1175 details: "URL is missing either `host`, `path`, and/or `resource`."
1176 .to_string(),
1177 });
1178 }
1179 }
1180 Err(err) => {
1181 return Err(ParseError::InvalidComponentUrl {
1182 details: format!("Malformed URL: {err:?}."),
1183 });
1184 }
1185 }
1186 Ok(())
1188 }
1189
1190 pub fn is_relative(&self) -> bool {
1191 matches!(url::Url::parse(&self.0), Err(url::ParseError::RelativeUrlWithoutBase))
1192 }
1193
1194 pub fn scheme(&self) -> Option<String> {
1195 url::Url::parse(&self.0).ok().map(|u| u.scheme().into())
1196 }
1197
1198 pub fn resource(&self) -> Option<String> {
1199 url::Url::parse(&self.0).ok().map(|u| u.fragment().map(str::to_string)).flatten()
1200 }
1201
1202 pub fn as_str(&self) -> &str {
1203 &*self.0
1204 }
1205}
1206
1207impl FromStr for Url {
1208 type Err = ParseError;
1209
1210 fn from_str(url: &str) -> Result<Self, Self::Err> {
1211 Self::new(url)
1212 }
1213}
1214
1215impl From<Url> for String {
1216 fn from(url: Url) -> String {
1217 url.0.into()
1218 }
1219}
1220
1221impl fmt::Display for Url {
1222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1223 fmt::Display::fmt(&self.0, f)
1224 }
1225}
1226
1227impl ser::Serialize for Url {
1228 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1229 where
1230 S: ser::Serializer,
1231 {
1232 self.to_string().serialize(serializer)
1233 }
1234}
1235
1236impl<'de> de::Deserialize<'de> for Url {
1237 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1238 where
1239 D: de::Deserializer<'de>,
1240 {
1241 struct Visitor;
1242
1243 impl<'de> de::Visitor<'de> for Visitor {
1244 type Value = Url;
1245
1246 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1247 f.write_str("a non-empty URL no more than 4096 characters in length")
1248 }
1249
1250 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
1251 where
1252 E: de::Error,
1253 {
1254 s.parse().map_err(|err| match err {
1255 ParseError::InvalidComponentUrl { details: _ } => {
1256 E::invalid_value(de::Unexpected::Str(s), &"a valid URL")
1257 }
1258 ParseError::TooLong | ParseError::Empty => E::invalid_length(
1259 s.len(),
1260 &"a non-empty URL no more than 4096 characters in length",
1261 ),
1262 e => {
1263 panic!("unexpected parse error: {:?}", e);
1264 }
1265 })
1266 }
1267 }
1268 deserializer.deserialize_string(Visitor)
1269 }
1270}
1271
1272impl PartialEq<&str> for Url {
1273 fn eq(&self, o: &&str) -> bool {
1274 &*self.0 == *o
1275 }
1276}
1277
1278impl PartialEq<String> for Url {
1279 fn eq(&self, o: &String) -> bool {
1280 &*self.0 == *o
1281 }
1282}
1283
1284#[derive(Serialize, Clone, Debug, Eq, Hash, PartialEq)]
1286pub struct UrlScheme(FlyStr);
1287
1288impl UrlScheme {
1289 pub fn new(url_scheme: impl AsRef<str> + Into<String>) -> Result<Self, ParseError> {
1294 Self::validate(url_scheme.as_ref())?;
1295 Ok(UrlScheme(FlyStr::new(url_scheme)))
1296 }
1297
1298 pub fn validate(url_scheme: &str) -> Result<(), ParseError> {
1301 if url_scheme.is_empty() {
1302 return Err(ParseError::Empty);
1303 }
1304 if url_scheme.len() > MAX_NAME_LENGTH {
1305 return Err(ParseError::TooLong);
1306 }
1307 let mut iter = url_scheme.chars();
1308 let first_char = iter.next().unwrap();
1309 if !first_char.is_ascii_lowercase() {
1310 return Err(ParseError::InvalidValue);
1311 }
1312 if let Some(_) = iter.find(|&c| {
1313 !c.is_ascii_lowercase() && !c.is_ascii_digit() && c != '.' && c != '+' && c != '-'
1314 }) {
1315 return Err(ParseError::InvalidValue);
1316 }
1317 Ok(())
1318 }
1319
1320 pub fn as_str(&self) -> &str {
1321 &*self.0
1322 }
1323}
1324
1325impl fmt::Display for UrlScheme {
1326 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1327 fmt::Display::fmt(&self.0, f)
1328 }
1329}
1330
1331impl FromStr for UrlScheme {
1332 type Err = ParseError;
1333
1334 fn from_str(s: &str) -> Result<Self, Self::Err> {
1335 Self::new(s)
1336 }
1337}
1338
1339impl From<UrlScheme> for String {
1340 fn from(u: UrlScheme) -> String {
1341 u.0.into()
1342 }
1343}
1344
1345impl<'de> de::Deserialize<'de> for UrlScheme {
1346 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1347 where
1348 D: de::Deserializer<'de>,
1349 {
1350 struct Visitor;
1351
1352 impl<'de> de::Visitor<'de> for Visitor {
1353 type Value = UrlScheme;
1354
1355 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1356 f.write_str("a non-empty URL scheme no more than 100 characters in length")
1357 }
1358
1359 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
1360 where
1361 E: de::Error,
1362 {
1363 s.parse().map_err(|err| match err {
1364 ParseError::InvalidValue => {
1365 E::invalid_value(de::Unexpected::Str(s), &"a valid URL scheme")
1366 }
1367 ParseError::TooLong | ParseError::Empty => E::invalid_length(
1368 s.len(),
1369 &"a non-empty URL scheme no more than 100 characters in length",
1370 ),
1371 e => {
1372 panic!("unexpected parse error: {:?}", e);
1373 }
1374 })
1375 }
1376 }
1377 deserializer.deserialize_string(Visitor)
1378 }
1379}
1380
1381#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
1385#[serde(rename_all = "snake_case")]
1386pub enum Durability {
1387 Transient,
1388 SingleRun,
1390}
1391
1392symmetrical_enums!(Durability, fdecl::Durability, Transient, SingleRun);
1393
1394#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1398#[serde(rename_all = "snake_case")]
1399pub enum StartupMode {
1400 Lazy,
1401 Eager,
1402}
1403
1404impl StartupMode {
1405 pub fn is_lazy(&self) -> bool {
1406 matches!(self, StartupMode::Lazy)
1407 }
1408}
1409
1410symmetrical_enums!(StartupMode, fdecl::StartupMode, Lazy, Eager);
1411
1412impl Default for StartupMode {
1413 fn default() -> Self {
1414 Self::Lazy
1415 }
1416}
1417
1418#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1422#[serde(rename_all = "snake_case")]
1423pub enum OnTerminate {
1424 None,
1425 Reboot,
1426}
1427
1428symmetrical_enums!(OnTerminate, fdecl::OnTerminate, None, Reboot);
1429
1430impl Default for OnTerminate {
1431 fn default() -> Self {
1432 Self::None
1433 }
1434}
1435
1436#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
1441#[serde(rename_all = "snake_case")]
1442pub enum AllowedOffers {
1443 StaticOnly,
1444 StaticAndDynamic,
1445}
1446
1447symmetrical_enums!(AllowedOffers, fdecl::AllowedOffers, StaticOnly, StaticAndDynamic);
1448
1449impl Default for AllowedOffers {
1450 fn default() -> Self {
1451 Self::StaticOnly
1452 }
1453}
1454
1455#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
1459#[serde(rename_all = "snake_case")]
1460pub enum DependencyType {
1461 Strong,
1462 Weak,
1463}
1464
1465symmetrical_enums!(DependencyType, fdecl::DependencyType, Strong, Weak);
1466
1467impl Default for DependencyType {
1468 fn default() -> Self {
1469 Self::Strong
1470 }
1471}
1472
1473#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Copy)]
1477#[serde(rename_all = "snake_case")]
1478pub enum Availability {
1479 Required,
1480 Optional,
1481 SameAsTarget,
1482 Transitional,
1483}
1484
1485symmetrical_enums!(
1486 Availability,
1487 fdecl::Availability,
1488 Required,
1489 Optional,
1490 SameAsTarget,
1491 Transitional
1492);
1493
1494impl Display for Availability {
1495 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1496 match self {
1497 Availability::Required => write!(f, "Required"),
1498 Availability::Optional => write!(f, "Optional"),
1499 Availability::SameAsTarget => write!(f, "SameAsTarget"),
1500 Availability::Transitional => write!(f, "Transitional"),
1501 }
1502 }
1503}
1504
1505impl Default for Availability {
1507 fn default() -> Self {
1508 Self::Required
1509 }
1510}
1511
1512impl PartialOrd for Availability {
1513 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1514 match (*self, *other) {
1515 (Availability::Transitional, Availability::Optional)
1516 | (Availability::Transitional, Availability::Required)
1517 | (Availability::Optional, Availability::Required) => Some(cmp::Ordering::Less),
1518 (Availability::Optional, Availability::Transitional)
1519 | (Availability::Required, Availability::Transitional)
1520 | (Availability::Required, Availability::Optional) => Some(cmp::Ordering::Greater),
1521 (Availability::Required, Availability::Required)
1522 | (Availability::Optional, Availability::Optional)
1523 | (Availability::Transitional, Availability::Transitional)
1524 | (Availability::SameAsTarget, Availability::SameAsTarget) => {
1525 Some(cmp::Ordering::Equal)
1526 }
1527 (Availability::SameAsTarget, _) | (_, Availability::SameAsTarget) => None,
1528 }
1529 }
1530}
1531
1532#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Copy)]
1538#[serde(rename_all = "snake_case")]
1539pub enum DeliveryType {
1540 Immediate,
1541 OnReadable,
1542}
1543
1544#[cfg(fuchsia_api_level_at_least = "HEAD")]
1545impl TryFrom<fdecl::DeliveryType> for DeliveryType {
1546 type Error = fdecl::DeliveryType;
1547
1548 fn try_from(value: fdecl::DeliveryType) -> Result<Self, Self::Error> {
1549 match value {
1550 fdecl::DeliveryType::Immediate => Ok(DeliveryType::Immediate),
1551 fdecl::DeliveryType::OnReadable => Ok(DeliveryType::OnReadable),
1552 fdecl::DeliveryTypeUnknown!() => Err(value),
1553 }
1554 }
1555}
1556
1557#[cfg(fuchsia_api_level_at_least = "HEAD")]
1558impl From<DeliveryType> for fdecl::DeliveryType {
1559 fn from(value: DeliveryType) -> Self {
1560 match value {
1561 DeliveryType::Immediate => fdecl::DeliveryType::Immediate,
1562 DeliveryType::OnReadable => fdecl::DeliveryType::OnReadable,
1563 }
1564 }
1565}
1566
1567impl Display for DeliveryType {
1568 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1569 match self {
1570 DeliveryType::Immediate => write!(f, "Immediate"),
1571 DeliveryType::OnReadable => write!(f, "OnReadable"),
1572 }
1573 }
1574}
1575
1576impl Default for DeliveryType {
1577 fn default() -> Self {
1578 Self::Immediate
1579 }
1580}
1581
1582#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
1583#[serde(rename_all = "snake_case")]
1584pub enum StorageId {
1585 StaticInstanceId,
1586 StaticInstanceIdOrMoniker,
1587}
1588
1589symmetrical_enums!(StorageId, fdecl::StorageId, StaticInstanceId, StaticInstanceIdOrMoniker);
1590
1591#[cfg(test)]
1592mod tests {
1593 use super::*;
1594 use assert_matches::assert_matches;
1595 use serde_json::json;
1596 use std::iter::repeat;
1597
1598 macro_rules! expect_ok {
1599 ($type_:ty, $($input:tt)+) => {
1600 assert_matches!(
1601 serde_json::from_str::<$type_>(&json!($($input)*).to_string()),
1602 Ok(_)
1603 );
1604 };
1605 }
1606
1607 macro_rules! expect_ok_no_serialize {
1608 ($type_:ty, $($input:tt)+) => {
1609 assert_matches!(
1610 ($($input)*).parse::<$type_>(),
1611 Ok(_)
1612 );
1613 };
1614 }
1615
1616 macro_rules! expect_err_no_serialize {
1617 ($type_:ty, $err:pat, $($input:tt)+) => {
1618 assert_matches!(
1619 ($($input)*).parse::<$type_>(),
1620 Err($err)
1621 );
1622 };
1623 }
1624
1625 macro_rules! expect_err {
1626 ($type_:ty, $err:pat, $($input:tt)+) => {
1627 assert_matches!(
1628 ($($input)*).parse::<$type_>(),
1629 Err($err)
1630 );
1631 assert_matches!(
1632 serde_json::from_str::<$type_>(&json!($($input)*).to_string()),
1633 Err(_)
1634 );
1635 };
1636 }
1637
1638 #[test]
1639 fn test_valid_name() {
1640 expect_ok!(Name, "foo");
1641 expect_ok!(Name, "Foo");
1642 expect_ok!(Name, "O123._-");
1643 expect_ok!(Name, "_O123._-");
1644 expect_ok!(Name, repeat("x").take(255).collect::<String>());
1645 }
1646
1647 #[test]
1648 fn test_invalid_name() {
1649 expect_err!(Name, ParseError::Empty, "");
1650 expect_err!(Name, ParseError::InvalidValue, "-");
1651 expect_err!(Name, ParseError::InvalidValue, ".");
1652 expect_err!(Name, ParseError::InvalidValue, "@&%^");
1653 expect_err!(Name, ParseError::TooLong, repeat("x").take(256).collect::<String>());
1654 }
1655
1656 #[test]
1657 fn test_valid_path() {
1658 expect_ok!(Path, "/foo");
1659 expect_ok!(Path, "/foo/bar");
1660 expect_ok!(Path, format!("/{}", repeat("x").take(100).collect::<String>()).as_str());
1661 expect_ok!(Path, repeat("/x").take(2047).collect::<String>().as_str());
1663 }
1664
1665 #[test]
1666 fn test_invalid_path() {
1667 expect_err!(Path, ParseError::Empty, "");
1668 expect_err!(Path, ParseError::InvalidValue, "/");
1669 expect_err!(Path, ParseError::InvalidValue, ".");
1670 expect_err!(Path, ParseError::NoLeadingSlash, "foo");
1671 expect_err!(Path, ParseError::NoLeadingSlash, "foo/");
1672 expect_err!(Path, ParseError::InvalidValue, "/foo/");
1673 expect_err!(Path, ParseError::InvalidValue, "/foo//bar");
1674 expect_err!(Path, ParseError::InvalidSegment, "/fo\0b/bar");
1675 expect_err!(Path, ParseError::InvalidSegment, "/.");
1676 expect_err!(Path, ParseError::InvalidSegment, "/foo/.");
1677 expect_err!(
1678 Path,
1679 ParseError::InvalidSegment,
1680 format!("/{}", repeat("x").take(256).collect::<String>()).as_str()
1681 );
1682 expect_err!(
1684 Path,
1685 ParseError::TooLong,
1686 repeat("/x").take(2048).collect::<String>().as_str()
1687 );
1688 }
1689
1690 #[test]
1692 fn test_path_methods() {
1693 let dot = RelativePath::dot();
1694 let prefix = Path::new("/some/path").unwrap();
1695 let suffix = RelativePath::new("another/path").unwrap();
1696 let segment = Name::new("segment").unwrap();
1697
1698 let mut path = prefix.clone();
1699 assert!(path.extend(suffix.clone()));
1700 assert_eq!(path, "/some/path/another/path".parse().unwrap());
1701 assert_eq!(
1702 path.split(),
1703 [
1704 BorrowedName::new("some").unwrap(),
1705 BorrowedName::new("path").unwrap(),
1706 BorrowedName::new("another").unwrap(),
1707 BorrowedName::new("path").unwrap(),
1708 ]
1709 );
1710
1711 let mut path = prefix.clone();
1712 assert!(path.extend(dot.clone()));
1713 assert_eq!(path, "/some/path".parse().unwrap());
1714
1715 let mut path = prefix.clone();
1716 assert!(path.push(segment.clone()));
1717 assert_eq!(path, "/some/path/segment".parse().unwrap());
1718 assert!(path.push(segment.clone()));
1719 assert_eq!(path, "/some/path/segment/segment".parse().unwrap());
1720 assert_eq!(
1721 path.split(),
1722 [
1723 BorrowedName::new("some").unwrap(),
1724 BorrowedName::new("path").unwrap(),
1725 BorrowedName::new("segment").unwrap(),
1726 BorrowedName::new("segment").unwrap(),
1727 ]
1728 );
1729
1730 let long_path =
1731 Path::new(format!("{}/xx", repeat("/x").take(4092 / 2).collect::<String>())).unwrap();
1732 let mut path = long_path.clone();
1733 assert!(!path.push("a".parse().unwrap()));
1735 assert_eq!(path, long_path);
1736 assert!(!path.extend("a".parse().unwrap()));
1737 assert_eq!(path, long_path);
1738 }
1739
1740 #[test]
1741 fn test_valid_namespace_path() {
1742 expect_ok_no_serialize!(NamespacePath, "/");
1743 expect_ok_no_serialize!(NamespacePath, "/foo");
1744 expect_ok_no_serialize!(NamespacePath, "/foo/bar");
1745 expect_ok_no_serialize!(
1746 NamespacePath,
1747 format!("/{}", repeat("x").take(100).collect::<String>()).as_str()
1748 );
1749 expect_ok_no_serialize!(
1751 NamespacePath,
1752 repeat("/x").take(2047).collect::<String>().as_str()
1753 );
1754 }
1755
1756 #[test]
1757 fn test_invalid_namespace_path() {
1758 expect_err_no_serialize!(NamespacePath, ParseError::Empty, "");
1759 expect_err_no_serialize!(NamespacePath, ParseError::InvalidValue, ".");
1760 expect_err_no_serialize!(NamespacePath, ParseError::NoLeadingSlash, "foo");
1761 expect_err_no_serialize!(NamespacePath, ParseError::NoLeadingSlash, "foo/");
1762 expect_err_no_serialize!(NamespacePath, ParseError::InvalidValue, "/foo/");
1763 expect_err_no_serialize!(NamespacePath, ParseError::InvalidValue, "/foo//bar");
1764 expect_err_no_serialize!(NamespacePath, ParseError::InvalidSegment, "/fo\0b/bar");
1765 expect_err_no_serialize!(NamespacePath, ParseError::InvalidSegment, "/.");
1766 expect_err_no_serialize!(NamespacePath, ParseError::InvalidSegment, "/foo/.");
1767 expect_err_no_serialize!(
1768 NamespacePath,
1769 ParseError::InvalidSegment,
1770 format!("/{}", repeat("x").take(256).collect::<String>()).as_str()
1771 );
1772 expect_err_no_serialize!(
1774 Path,
1775 ParseError::TooLong,
1776 repeat("/x").take(2048).collect::<String>().as_str()
1777 );
1778 }
1779
1780 #[test]
1781 fn test_path_parent_basename() {
1782 let path = Path::new("/foo").unwrap();
1783 assert_eq!((path.parent().to_string().as_str(), path.basename().as_str()), ("/", "foo"));
1784 let path = Path::new("/foo/bar").unwrap();
1785 assert_eq!((path.parent().to_string().as_str(), path.basename().as_str()), ("/foo", "bar"));
1786 let path = Path::new("/foo/bar/baz").unwrap();
1787 assert_eq!(
1788 (path.parent().to_string().as_str(), path.basename().as_str()),
1789 ("/foo/bar", "baz")
1790 );
1791 }
1792
1793 #[test]
1794 fn test_separated_path() {
1795 fn test_path(path: SeparatedPath, in_expected_segments: Vec<&str>) {
1796 let expected_segments: Vec<&BorrowedName> =
1797 in_expected_segments.iter().map(|s| BorrowedName::new(*s).unwrap()).collect();
1798 let segments: Vec<&BorrowedName> = path.iter_segments().collect();
1799 assert_eq!(segments, expected_segments);
1800 let borrowed_path = path.as_ref();
1801 let segments: Vec<&BorrowedName> = borrowed_path.iter_segments().collect();
1802 assert_eq!(segments, expected_segments);
1803 let owned_path = borrowed_path.to_owned();
1804 assert_eq!(path, owned_path);
1805 let expected_fmt = in_expected_segments.join("/");
1806 assert_eq!(format!("{path}"), expected_fmt);
1807 assert_eq!(format!("{owned_path}"), expected_fmt);
1808 }
1809 test_path(
1810 SeparatedPath { dirname: ".".parse().unwrap(), basename: "foo".parse().unwrap() },
1811 vec!["foo"],
1812 );
1813 test_path(
1814 SeparatedPath { dirname: "bar".parse().unwrap(), basename: "foo".parse().unwrap() },
1815 vec!["bar", "foo"],
1816 );
1817 test_path(
1818 SeparatedPath { dirname: "bar/baz".parse().unwrap(), basename: "foo".parse().unwrap() },
1819 vec!["bar", "baz", "foo"],
1820 );
1821 }
1822
1823 #[test]
1824 fn test_valid_relative_path() {
1825 expect_ok!(RelativePath, ".");
1826 expect_ok!(RelativePath, "foo");
1827 expect_ok!(RelativePath, "foo/bar");
1828 expect_ok!(RelativePath, &format!("x{}", repeat("/x").take(2047).collect::<String>()));
1829 }
1830
1831 #[test]
1832 fn test_invalid_relative_path() {
1833 expect_err!(RelativePath, ParseError::Empty, "");
1834 expect_err!(RelativePath, ParseError::InvalidValue, "/");
1835 expect_err!(RelativePath, ParseError::InvalidValue, "/foo");
1836 expect_err!(RelativePath, ParseError::InvalidValue, "foo/");
1837 expect_err!(RelativePath, ParseError::InvalidValue, "/foo/");
1838 expect_err!(RelativePath, ParseError::InvalidValue, "foo//bar");
1839 expect_err!(RelativePath, ParseError::InvalidSegment, "..");
1840 expect_err!(RelativePath, ParseError::InvalidSegment, "foo/..");
1841 expect_err!(
1842 RelativePath,
1843 ParseError::TooLong,
1844 &format!("x{}", repeat("/x").take(2048).collect::<String>())
1845 );
1846 }
1847
1848 #[test]
1850 fn test_relative_path_methods() {
1851 let dot = RelativePath::dot();
1852 let prefix = RelativePath::new("some/path").unwrap();
1853 let suffix = RelativePath::new("another/path").unwrap();
1854 let segment = Name::new("segment").unwrap();
1855
1856 let mut path = prefix.clone();
1857 assert!(path.extend(suffix.clone()));
1858 assert_eq!(path, "some/path/another/path".parse().unwrap());
1859 assert_eq!(
1860 path.split(),
1861 [
1862 BorrowedName::new("some").unwrap(),
1863 BorrowedName::new("path").unwrap(),
1864 BorrowedName::new("another").unwrap(),
1865 BorrowedName::new("path").unwrap(),
1866 ]
1867 );
1868 assert_eq!(path.pop_front(), Some(Name::new("some").unwrap()));
1869 assert_eq!(path.pop_front(), Some(Name::new("path").unwrap()));
1870 assert_eq!(path.pop_front(), Some(Name::new("another").unwrap()));
1871 assert_eq!(path.pop_front(), Some(Name::new("path").unwrap()));
1872 assert_eq!(path.pop_front(), None);
1873
1874 let mut path = prefix.clone();
1875 assert!(path.extend(dot.clone()));
1876 assert_eq!(path, "some/path".parse().unwrap());
1877 let mut path = dot.clone();
1878 assert!(path.extend(suffix));
1879 assert_eq!(path, "another/path".parse().unwrap());
1880 let mut path = dot.clone();
1881 assert!(path.extend(dot.clone()));
1882 assert_eq!(path, RelativePath::dot());
1883
1884 let mut path = prefix.clone();
1885 assert!(path.push(segment.clone()));
1886 assert_eq!(path, "some/path/segment".parse().unwrap());
1887 assert!(path.push(segment.clone()));
1888 assert_eq!(path, "some/path/segment/segment".parse().unwrap());
1889 assert_eq!(
1890 path.split(),
1891 [
1892 BorrowedName::new("some").unwrap(),
1893 BorrowedName::new("path").unwrap(),
1894 BorrowedName::new("segment").unwrap(),
1895 BorrowedName::new("segment").unwrap(),
1896 ]
1897 );
1898
1899 let mut path = dot.clone();
1900 assert!(path.push(segment.clone()));
1901 assert_eq!(path, "segment".parse().unwrap());
1902
1903 let long_path =
1904 RelativePath::new(format!("{}x", repeat("x/").take(4094 / 2).collect::<String>()))
1905 .unwrap();
1906 let mut path = long_path.clone();
1907 assert!(!path.push("a".parse().unwrap()));
1909 assert_eq!(path, long_path);
1910 assert!(!path.extend("a".parse().unwrap()));
1911 assert_eq!(path, long_path);
1912 }
1913
1914 #[test]
1915 fn test_valid_url() {
1916 expect_ok!(Url, "a://foo");
1917 expect_ok!(Url, "#relative-url");
1918 expect_ok!(Url, &format!("a://{}", repeat("x").take(4092).collect::<String>()));
1919 }
1920
1921 #[test]
1922 fn test_invalid_url() {
1923 expect_err!(Url, ParseError::Empty, "");
1924 expect_err!(Url, ParseError::InvalidComponentUrl { .. }, "foo");
1925 expect_err!(
1926 Url,
1927 ParseError::TooLong,
1928 &format!("a://{}", repeat("x").take(4093).collect::<String>())
1929 );
1930 }
1931
1932 #[test]
1933 fn test_valid_url_scheme() {
1934 expect_ok!(UrlScheme, "fuch.sia-pkg+0");
1935 expect_ok!(UrlScheme, &format!("{}", repeat("f").take(255).collect::<String>()));
1936 }
1937
1938 #[test]
1939 fn test_invalid_url_scheme() {
1940 expect_err!(UrlScheme, ParseError::Empty, "");
1941 expect_err!(UrlScheme, ParseError::InvalidValue, "0fuch.sia-pkg+0");
1942 expect_err!(UrlScheme, ParseError::InvalidValue, "fuchsia_pkg");
1943 expect_err!(UrlScheme, ParseError::InvalidValue, "FUCHSIA-PKG");
1944 expect_err!(
1945 UrlScheme,
1946 ParseError::TooLong,
1947 &format!("{}", repeat("f").take(256).collect::<String>())
1948 );
1949 }
1950
1951 #[test]
1952 fn test_name_error_message() {
1953 let input = r#"
1954 "foo$"
1955 "#;
1956 let err = serde_json::from_str::<Name>(input).expect_err("must fail");
1957 assert_eq!(
1958 err.to_string(),
1959 "invalid value: string \"foo$\", expected a name \
1960 that consists of [A-Za-z0-9_.-] and starts with [A-Za-z0-9_] \
1961 at line 2 column 18"
1962 );
1963 assert_eq!(err.line(), 2);
1964 assert_eq!(err.column(), 18);
1965 }
1966
1967 #[test]
1968 fn test_path_error_message() {
1969 let input = r#"
1970 "foo";
1971 "#;
1972 let err = serde_json::from_str::<Path>(input).expect_err("must fail");
1973 assert_eq!(
1974 err.to_string(),
1975 "invalid value: string \"foo\", expected a path with leading `/` and non-empty \
1976 segments, where each segment is no \
1977 more than fuchsia.io/MAX_NAME_LENGTH bytes in length, cannot be . or .., \
1978 and cannot contain embedded NULs at line 2 column 17"
1979 );
1980
1981 assert_eq!(err.line(), 2);
1982 assert_eq!(err.column(), 17);
1983 }
1984
1985 #[test]
1986 fn test_url_error_message() {
1987 let input = r#"
1988 "foo";
1989 "#;
1990 let err = serde_json::from_str::<Url>(input).expect_err("must fail");
1991 assert_eq!(
1992 err.to_string(),
1993 "invalid value: string \"foo\", expected a valid URL at line 2 \
1994 column 17"
1995 );
1996 assert_eq!(err.line(), 2);
1997 assert_eq!(err.column(), 17);
1998 }
1999
2000 #[test]
2001 fn test_url_scheme_error_message() {
2002 let input = r#"
2003 "9fuchsia_pkg"
2004 "#;
2005 let err = serde_json::from_str::<UrlScheme>(input).expect_err("must fail");
2006 assert_eq!(
2007 err.to_string(),
2008 "invalid value: string \"9fuchsia_pkg\", expected a valid URL scheme at line 2 column 26"
2009 );
2010 assert_eq!(err.line(), 2);
2011 assert_eq!(err.column(), 26);
2012 }
2013
2014 #[test]
2015 fn test_symmetrical_enums() {
2016 mod a {
2017 #[derive(Debug, PartialEq, Eq)]
2018 pub enum Streetlight {
2019 Green,
2020 Yellow,
2021 Red,
2022 }
2023 }
2024
2025 mod b {
2026 #[derive(Debug, PartialEq, Eq)]
2027 pub enum Streetlight {
2028 Green,
2029 Yellow,
2030 Red,
2031 }
2032 }
2033
2034 symmetrical_enums!(a::Streetlight, b::Streetlight, Green, Yellow, Red);
2035
2036 assert_eq!(a::Streetlight::Green, b::Streetlight::Green.into());
2037 assert_eq!(a::Streetlight::Yellow, b::Streetlight::Yellow.into());
2038 assert_eq!(a::Streetlight::Red, b::Streetlight::Red.into());
2039 assert_eq!(b::Streetlight::Green, a::Streetlight::Green.into());
2040 assert_eq!(b::Streetlight::Yellow, a::Streetlight::Yellow.into());
2041 assert_eq!(b::Streetlight::Red, a::Streetlight::Red.into());
2042 }
2043}