path_serializer.rs 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. //! path_serializer is used in cases where we need to serialize relative Path
  2. //! and PathBuf objects in a way that's cross-platform.
  3. //!
  4. //! This is used for the snapshot testing system to make sure that snapshots
  5. //! that reference local paths that are generated on Windows don't fail when run
  6. //! in systems that use a different directory separator.
  7. //!
  8. //! To use, annotate your PathBuf or Option<PathBuf> field with the correct
  9. //! serializer function:
  10. //!
  11. //! ```ignore
  12. //! # use std::path::PathBuf;
  13. //! # use serde::{Serialize, Deserialize};
  14. //!
  15. //! #[derive(Serialize, Deserialize)]
  16. //! struct Mine {
  17. //! name: String,
  18. //!
  19. //! // Use 'crate' instead of librojo if writing code inside Rojo
  20. //! #[serde(serialize_with = "librojo::path_serializer::serialize")]
  21. //! source_path: PathBuf,
  22. //!
  23. //! #[serde(serialize_with = "librojo::path_serializer::serialize_option")]
  24. //! maybe_path: Option<PathBuf>,
  25. //! }
  26. //! ```
  27. //!
  28. //! **The methods in this module can only handle relative paths, since absolute
  29. //! paths are never portable.**
  30. use std::path::{Component, Path};
  31. use serde::Serializer;
  32. pub fn serialize_option<S, T>(maybe_path: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
  33. where
  34. S: Serializer,
  35. T: AsRef<Path>,
  36. {
  37. match maybe_path {
  38. Some(path) => serialize(path, serializer),
  39. None => serializer.serialize_none(),
  40. }
  41. }
  42. pub fn serialize<S, T>(path: T, serializer: S) -> Result<S::Ok, S::Error>
  43. where
  44. S: Serializer,
  45. T: AsRef<Path>,
  46. {
  47. let path = path.as_ref();
  48. assert!(
  49. path.is_relative(),
  50. "path_serializer can only handle relative paths"
  51. );
  52. let mut output = String::new();
  53. for component in path.components() {
  54. if !output.is_empty() {
  55. output.push('/');
  56. }
  57. match component {
  58. Component::CurDir => output.push('.'),
  59. Component::ParentDir => output.push_str(".."),
  60. Component::Normal(piece) => output.push_str(piece.to_str().unwrap()),
  61. _ => panic!("path_serializer cannot handle absolute path components"),
  62. }
  63. }
  64. serializer.serialize_str(&output)
  65. }