json_crawler/
lib.rs

1//! Library to crawl Json using the pointer syntax and return useful errors.
2//! Documentation is a work in progress.
3use error::ParseTarget;
4pub use error::{CrawlerError, CrawlerResult};
5pub use iter::*;
6use serde::de::DeserializeOwned;
7use serde::Deserialize;
8// Currently the only way to create a crawler is from a serde_json::Value, so we
9// might as well re-export it.
10// doc(no_inline) means that the re-export will be clear in the docs.
11#[doc(no_inline)]
12pub use serde_json::Value;
13use std::fmt::Display;
14use std::ops::ControlFlow;
15use std::str::FromStr;
16use std::sync::Arc;
17
18mod error;
19mod iter;
20
21/// Trait to represent a JsonCrawler that may own or borrow from the original
22/// `serde_json::Value`.
23pub trait JsonCrawler
24where
25    Self: Sized,
26{
27    type BorrowTo<'a>: JsonCrawler
28    where
29        Self: 'a;
30    type IterMut<'a>: JsonCrawlerIterator<Item = Self::BorrowTo<'a>>
31    where
32        Self: 'a;
33    type IntoIter: JsonCrawlerIterator<Item = Self>;
34    fn navigate_pointer(self, new_path: impl AsRef<str>) -> CrawlerResult<Self>;
35    fn navigate_index(self, index: usize) -> CrawlerResult<Self>;
36    fn borrow_pointer(&mut self, path: impl AsRef<str>) -> CrawlerResult<Self::BorrowTo<'_>>;
37    fn borrow_index(&mut self, index: usize) -> CrawlerResult<Self::BorrowTo<'_>>;
38    fn borrow_mut(&mut self) -> Self::BorrowTo<'_>;
39    fn try_into_iter(self) -> CrawlerResult<Self::IntoIter>;
40    fn try_iter_mut(&mut self) -> CrawlerResult<Self::IterMut<'_>>;
41    fn path_exists(&self, path: &str) -> bool;
42    fn get_path(&self) -> String;
43    fn get_source(&self) -> Arc<String>;
44    fn take_value<T: DeserializeOwned>(&mut self) -> CrawlerResult<T>;
45    fn take_value_pointer<T: DeserializeOwned>(
46        &mut self,
47        path: impl AsRef<str>,
48    ) -> CrawlerResult<T>;
49    fn borrow_value<T: for<'de> Deserialize<'de>>(&self) -> CrawlerResult<T>;
50    fn borrow_value_pointer<T: for<'de> Deserialize<'de>>(
51        &self,
52        path: impl AsRef<str>,
53    ) -> CrawlerResult<T>;
54    /// For use when you want to try and take value that could be at multiple
55    /// valid locations. Returns an error message that notes that all valid
56    /// locations were attempted.
57    ///
58    /// # Usage
59    /// ```no_run
60    /// # use json_crawler::*;
61    /// # let mut crawler = JsonCrawlerOwned::new(String::new(), serde_json::Value::Null);
62    /// // Output will be an error that path should contain "header" and "headerName", if crawler contains neither.
63    /// let output: CrawlerResult<String> = crawler.take_value_pointers(&["header", "headerName"]);
64    /// ```
65    fn take_value_pointers<T: DeserializeOwned, S: AsRef<str>>(
66        &mut self,
67        paths: &[S],
68    ) -> CrawlerResult<T>;
69    /// For use when you want to apply some operations that return Option, but
70    /// still return an error with context if they fail. For convenience,
71    /// closure return type is fallible, allowing you to see the cause of the
72    /// error at the failure point as well, if you have it.
73    ///
74    /// # Usage
75    /// ```no_run
76    /// # use json_crawler::*;
77    /// # let mut crawler = JsonCrawlerOwned::new(String::new(), serde_json::Value::Null);
78    /// // Returns Ok(42) if crawler parses into 42.
79    /// // Returns parsing from string error, plus the message that output should be 42, if output fails to parse from string.
80    /// // Returns message that output should be 42, if output parses from string, but is not 42.
81    /// let forty_two: CrawlerResult<usize> = crawler.try_expect("Output should be 42", |crawler| {
82    ///     let num = crawler.take_and_parse_str::<usize>()?;
83    ///     if num == 42 {
84    ///         return Ok(Some(num));
85    ///     }
86    ///     Ok(None)
87    /// });
88    /// ```
89    fn try_expect<F, O>(&mut self, msg: impl ToString, f: F) -> CrawlerResult<O>
90    where
91        F: FnOnce(&mut Self) -> CrawlerResult<Option<O>>,
92    {
93        match f(self) {
94            Ok(Some(r)) => Ok(r),
95            Ok(None) => Err(CrawlerError::parsing(
96                self.get_path(),
97                self.get_source(),
98                crate::error::ParseTarget::Other(std::any::type_name::<O>().to_string()),
99                Some(msg.to_string()),
100            )),
101            // In this case, we've got a nested error, and should display both sets of context.
102            Err(e) => {
103                let msg = format!("Expected {} but encountered '{e}'", msg.to_string());
104                Err(CrawlerError::parsing(
105                    self.get_path(),
106                    self.get_source(),
107                    crate::error::ParseTarget::Other(std::any::type_name::<O>().to_string()),
108                    Some(msg),
109                ))
110            }
111        }
112    }
113    /// Take the value as a String, and apply FromStr to return the desired
114    /// type.
115    fn take_and_parse_str<F: FromStr>(&mut self) -> CrawlerResult<F>
116    where
117        F::Err: Display,
118    {
119        let as_string = self.take_value::<String>()?;
120        str::parse::<F>(as_string.as_str()).map_err(|e| {
121            CrawlerError::parsing(
122                self.get_path(),
123                self.get_source(),
124                crate::error::ParseTarget::Other(std::any::type_name::<F>().to_string()),
125                Some(format!("{e}")),
126            )
127        })
128    }
129    /// Try to apply each function in a list of functions, returning the first
130    /// Ok result, or the last Err result if none returned Ok.
131    ///
132    /// # Warning
133    /// If one of the functions mutates before failing, the mutation will still
134    /// be applied. Also, the mutations are applied sequentially - mutation 1
135    /// could impact mutation 2 for example.
136    fn try_functions<O>(
137        &mut self,
138        functions: impl IntoIterator<Item = fn(&mut Self) -> CrawlerResult<O>>,
139    ) -> CrawlerResult<O> {
140        let original_path = self.get_path();
141        let source_ptr = self.get_source();
142        let output = functions.into_iter().try_fold(Vec::new(), |mut acc, f| {
143            let res = f(self);
144            let e = match res {
145                Ok(ret) => return ControlFlow::Break(ret),
146                Err(e) => e,
147            };
148            acc.push(e);
149            ControlFlow::Continue(acc)
150        });
151        match output {
152            ControlFlow::Continue(c) => Err(CrawlerError::multiple_parse_error(
153                original_path,
154                source_ptr,
155                c,
156            )),
157            ControlFlow::Break(b) => Ok(b),
158        }
159    }
160    /// Apply `function` at the first path that exists in `paths`, returning an
161    /// error if none exist.
162    ///
163    /// # Warning
164    /// If one of the functions mutates before failing, the mutation will still
165    /// be applied. Also, the mutations are applied sequentially - mutation 1
166    /// could impact mutation 2 for example.
167    fn apply_function_at_paths<O>(
168        &mut self,
169        paths: &[impl AsRef<str>],
170        function: fn(Self::BorrowTo<'_>) -> O,
171    ) -> CrawlerResult<O> {
172        let output = paths
173            .iter()
174            .find_map(|path| self.borrow_pointer(path.as_ref()).ok().map(function));
175        match output {
176            None => Err(CrawlerError::paths_not_found(
177                self.get_path(),
178                self.get_source(),
179                paths.iter().map(|s| s.as_ref().to_string()).collect(),
180            )),
181            Some(o) => Ok(o),
182        }
183    }
184}
185
186#[derive(Clone, PartialEq, Debug)]
187pub struct JsonCrawlerOwned {
188    // Source is wrapped in an Arc as we are going to pass ownership when returning an error and we
189    // want it to be thread safe.
190    source: Arc<String>,
191    crawler: serde_json::Value,
192    path: PathList,
193}
194pub struct JsonCrawlerBorrowed<'a> {
195    // Source is wrapped in an Arc as we are going to pass ownership when returning an error and we
196    // want it to be thread safe.
197    source: Arc<String>,
198    crawler: &'a mut serde_json::Value,
199    path: PathList,
200}
201
202impl JsonCrawlerOwned {
203    /// Create a new JsonCrawler, where 'json' is the `serde_json::Value` that
204    /// you wish to crawl and 'source' represents a serialized copy of the same
205    /// `serde_json::Value`.
206    // TODO: Safer constructor that avoids 'source' being out of sync with 'json'
207    pub fn new(source: String, json: serde_json::Value) -> Self {
208        Self {
209            source: Arc::new(source),
210            crawler: json,
211            path: Default::default(),
212        }
213    }
214}
215
216impl<'a> JsonCrawler for JsonCrawlerBorrowed<'a> {
217    type BorrowTo<'b>
218        = JsonCrawlerBorrowed<'b>
219    where
220        Self: 'b;
221    type IterMut<'b>
222        = JsonCrawlerArrayIterMut<'b>
223    where
224        Self: 'b;
225    type IntoIter = JsonCrawlerArrayIterMut<'a>;
226    fn take_value_pointer<T: DeserializeOwned>(
227        &mut self,
228        path: impl AsRef<str>,
229    ) -> CrawlerResult<T> {
230        let mut path_clone = self.path.clone();
231        path_clone.push(JsonPath::pointer(path.as_ref()));
232        serde_json::from_value(
233            self.crawler
234                .pointer_mut(path.as_ref())
235                .map(|v| v.take())
236                .ok_or_else(|| CrawlerError::navigation(&path_clone, self.source.clone()))?,
237        )
238        .map_err(|e| {
239            CrawlerError::parsing(
240                &path_clone,
241                self.source.clone(),
242                ParseTarget::Other(std::any::type_name::<T>().to_string()),
243                Some(format!("{e}")),
244            )
245        })
246    }
247    fn borrow_pointer(&mut self, path: impl AsRef<str>) -> CrawlerResult<Self::BorrowTo<'_>> {
248        let mut path_clone = self.path.clone();
249        path_clone.push(JsonPath::pointer(path.as_ref()));
250        let crawler = self
251            .crawler
252            .pointer_mut(path.as_ref())
253            .ok_or_else(|| CrawlerError::navigation(&path_clone, self.source.clone()))?;
254        Ok(JsonCrawlerBorrowed {
255            source: self.source.clone(),
256            crawler,
257            path: path_clone,
258        })
259    }
260    fn navigate_pointer(self, path: impl AsRef<str>) -> CrawlerResult<Self> {
261        let mut path_clone = self.path.clone();
262        path_clone.push(JsonPath::pointer(path.as_ref()));
263        let crawler = self
264            .crawler
265            .pointer_mut(path.as_ref())
266            .ok_or_else(|| CrawlerError::navigation(&path_clone, self.source.clone()))?;
267        Ok(Self {
268            source: self.source,
269            crawler,
270            path: path_clone,
271        })
272    }
273    fn try_into_iter(self) -> CrawlerResult<Self::IntoIter> {
274        let json_array = self.crawler.as_array_mut().ok_or_else(|| {
275            CrawlerError::parsing(&self.path, self.source.clone(), ParseTarget::Array, None)
276        })?;
277        let path_clone = self.path.clone();
278        let cur_back = json_array.len().saturating_sub(1);
279        Ok(JsonCrawlerArrayIterMut {
280            source: self.source,
281            array: json_array.iter_mut(),
282            path: path_clone,
283            cur_front: 0,
284            cur_back,
285        })
286    }
287    fn try_iter_mut(&mut self) -> CrawlerResult<Self::IterMut<'_>> {
288        let json_array = self.crawler.as_array_mut().ok_or_else(|| {
289            CrawlerError::parsing(&self.path, self.source.clone(), ParseTarget::Array, None)
290        })?;
291        let path_clone = self.path.clone();
292        let cur_back = json_array.len().saturating_sub(1);
293        Ok(JsonCrawlerArrayIterMut {
294            source: self.source.clone(),
295            array: json_array.iter_mut(),
296            path: path_clone,
297            cur_front: 0,
298            cur_back,
299        })
300    }
301    fn navigate_index(self, index: usize) -> CrawlerResult<Self> {
302        let mut path_clone = self.path.clone();
303        path_clone.push(JsonPath::IndexNum(index));
304        let crawler = self
305            .crawler
306            .get_mut(index)
307            .ok_or_else(|| CrawlerError::navigation(&path_clone, self.source.clone()))?;
308        Ok(Self {
309            source: self.source,
310            crawler,
311            path: path_clone,
312        })
313    }
314    fn borrow_index(&mut self, index: usize) -> CrawlerResult<Self::BorrowTo<'_>> {
315        let mut path_clone = self.path.clone();
316        path_clone.push(JsonPath::IndexNum(index));
317        let crawler = self
318            .crawler
319            .get_mut(index)
320            .ok_or_else(|| CrawlerError::navigation(&path_clone, self.source.clone()))?;
321        Ok(JsonCrawlerBorrowed {
322            source: self.source.clone(),
323            crawler,
324            path: path_clone,
325        })
326    }
327    fn borrow_mut(&mut self) -> Self::BorrowTo<'_> {
328        JsonCrawlerBorrowed {
329            source: self.source.clone(),
330            crawler: self.crawler,
331            path: self.path.to_owned(),
332        }
333    }
334    fn get_path(&self) -> String {
335        (&self.path).into()
336    }
337    fn take_value<T: DeserializeOwned>(&mut self) -> CrawlerResult<T> {
338        serde_json::from_value(self.crawler.take()).map_err(|e| {
339            CrawlerError::parsing(
340                &self.path,
341                self.source.clone(),
342                ParseTarget::Other(std::any::type_name::<T>().to_string()),
343                Some(format!("{e}")),
344            )
345        })
346    }
347    fn take_value_pointers<T: DeserializeOwned, S: AsRef<str>>(
348        &mut self,
349        paths: &[S],
350    ) -> CrawlerResult<T> {
351        let mut path_clone = self.path.clone();
352        let Some((found, path)) = paths
353            .iter()
354            .find_map(|p| self.crawler.pointer_mut(p.as_ref()).map(|v| (v.take(), p)))
355        else {
356            return Err(CrawlerError::paths_not_found(
357                path_clone,
358                self.source.clone(),
359                paths.iter().map(|s| s.as_ref().to_string()).collect(),
360            ));
361        };
362        path_clone.push(JsonPath::Pointer(path.as_ref().to_string()));
363        serde_json::from_value(found).map_err(|e| {
364            CrawlerError::parsing(
365                &path_clone,
366                self.source.clone(),
367                ParseTarget::Other(std::any::type_name::<T>().to_string()),
368                Some(format!("{e}")),
369            )
370        })
371    }
372    fn borrow_value<T: for<'de> Deserialize<'de>>(&self) -> CrawlerResult<T> {
373        T::deserialize(&*self.crawler).map_err(|e| {
374            CrawlerError::parsing(
375                &self.path,
376                self.source.clone(),
377                ParseTarget::Other(std::any::type_name::<T>().to_string()),
378                Some(format!("{e}")),
379            )
380        })
381    }
382    fn borrow_value_pointer<T: for<'de> Deserialize<'de>>(
383        &self,
384        path: impl AsRef<str>,
385    ) -> CrawlerResult<T> {
386        let mut path_clone = self.path.clone();
387        path_clone.push(JsonPath::pointer(path.as_ref()));
388        // Deserialize without taking ownership or cloning.
389        T::deserialize(
390            self.crawler
391                .pointer(path.as_ref())
392                .ok_or_else(|| CrawlerError::navigation(&path_clone, self.source.clone()))?,
393        )
394        .map_err(|e| {
395            CrawlerError::parsing(
396                &path_clone,
397                self.source.clone(),
398                ParseTarget::Other(std::any::type_name::<T>().to_string()),
399                Some(format!("{e}")),
400            )
401        })
402    }
403    fn path_exists(&self, path: &str) -> bool {
404        self.crawler.pointer(path).is_some()
405    }
406    fn get_source(&self) -> Arc<String> {
407        self.source.clone()
408    }
409}
410
411impl JsonCrawler for JsonCrawlerOwned {
412    type BorrowTo<'a>
413        = JsonCrawlerBorrowed<'a>
414    where
415        Self: 'a;
416    type IterMut<'a>
417        = JsonCrawlerArrayIterMut<'a>
418    where
419        Self: 'a;
420    type IntoIter = JsonCrawlerArrayIntoIter;
421    fn try_into_iter(self) -> CrawlerResult<Self::IntoIter> {
422        if let JsonCrawlerOwned {
423            source,
424            crawler: serde_json::Value::Array(array),
425            path,
426        } = self
427        {
428            let cur_back = array.len().saturating_sub(1);
429            return Ok(JsonCrawlerArrayIntoIter {
430                source,
431                array: array.into_iter(),
432                path,
433                cur_front: 0,
434                cur_back,
435            });
436        }
437        Err(CrawlerError::parsing(
438            &self.path,
439            self.source.clone(),
440            ParseTarget::Array,
441            None,
442        ))
443    }
444    fn try_iter_mut(&mut self) -> CrawlerResult<Self::IterMut<'_>> {
445        let json_array = self.crawler.as_array_mut().ok_or_else(|| {
446            CrawlerError::parsing(&self.path, self.source.clone(), ParseTarget::Array, None)
447        })?;
448        let path_clone = self.path.clone();
449        let cur_back = json_array.len().saturating_sub(1);
450        Ok(JsonCrawlerArrayIterMut {
451            source: self.source.clone(),
452            array: json_array.iter_mut(),
453            path: path_clone,
454            cur_front: 0,
455            cur_back,
456        })
457    }
458    fn navigate_pointer(self, new_path: impl AsRef<str>) -> CrawlerResult<Self> {
459        let Self {
460            source,
461            crawler: mut old_crawler,
462            mut path,
463        } = self;
464        path.push(JsonPath::pointer(new_path.as_ref()));
465        let crawler = old_crawler
466            .pointer_mut(new_path.as_ref())
467            .map(|v| v.take())
468            .ok_or_else(|| CrawlerError::navigation(&path, source.clone()))?;
469        Ok(Self {
470            source,
471            crawler,
472            path,
473        })
474    }
475    fn navigate_index(self, index: usize) -> CrawlerResult<Self> {
476        let Self {
477            source,
478            crawler: mut old_crawler,
479            mut path,
480        } = self;
481        path.push(JsonPath::IndexNum(index));
482        let crawler = old_crawler
483            .get_mut(index)
484            .map(|v| v.take())
485            .ok_or_else(|| CrawlerError::navigation(&path, source.clone()))?;
486        Ok(Self {
487            source,
488            crawler,
489            path,
490        })
491    }
492    fn borrow_pointer(&mut self, path: impl AsRef<str>) -> CrawlerResult<Self::BorrowTo<'_>> {
493        let mut path_clone = self.path.clone();
494        path_clone.push(JsonPath::Pointer(path.as_ref().to_owned()));
495        let crawler = self
496            .crawler
497            .pointer_mut(path.as_ref())
498            .ok_or_else(|| CrawlerError::navigation(&path_clone, self.source.clone()))?;
499        Ok(JsonCrawlerBorrowed {
500            source: self.source.clone(),
501            crawler,
502            path: path_clone,
503        })
504    }
505    fn borrow_index(&mut self, index: usize) -> CrawlerResult<Self::BorrowTo<'_>> {
506        let mut path_clone = self.path.clone();
507        path_clone.push(JsonPath::IndexNum(index));
508        let crawler = self
509            .crawler
510            .get_mut(index)
511            .ok_or_else(|| CrawlerError::navigation(&path_clone, self.source.clone()))?;
512        Ok(JsonCrawlerBorrowed {
513            source: self.source.clone(),
514            crawler,
515            path: path_clone,
516        })
517    }
518    fn borrow_mut(&mut self) -> Self::BorrowTo<'_> {
519        JsonCrawlerBorrowed {
520            source: self.source.clone(),
521            crawler: &mut self.crawler,
522            path: self.path.to_owned(),
523        }
524    }
525    fn take_value<T: DeserializeOwned>(&mut self) -> CrawlerResult<T> {
526        serde_json::from_value(self.crawler.take()).map_err(|e| {
527            CrawlerError::parsing(
528                &self.path,
529                self.source.clone(),
530                ParseTarget::Other(std::any::type_name::<T>().to_string()),
531                Some(format!("{e}")),
532            )
533        })
534    }
535    fn take_value_pointer<T: DeserializeOwned>(
536        &mut self,
537        path: impl AsRef<str>,
538    ) -> CrawlerResult<T> {
539        let mut path_clone = self.path.clone();
540        path_clone.push(JsonPath::pointer(path.as_ref()));
541        serde_json::from_value(
542            self.crawler
543                .pointer_mut(path.as_ref())
544                .map(|v| v.take())
545                .ok_or_else(|| CrawlerError::navigation(&path_clone, self.source.clone()))?,
546        )
547        .map_err(|e| {
548            CrawlerError::parsing(
549                &path_clone,
550                self.source.clone(),
551                ParseTarget::Other(std::any::type_name::<T>().to_string()),
552                Some(format!("{e}")),
553            )
554        })
555    }
556    fn take_value_pointers<T: DeserializeOwned, S: AsRef<str>>(
557        &mut self,
558        paths: &[S],
559    ) -> CrawlerResult<T> {
560        let mut path_clone = self.path.clone();
561        let Some((found, path)) = paths
562            .iter()
563            .find_map(|p| self.crawler.pointer_mut(p.as_ref()).map(|v| (v.take(), p)))
564        else {
565            return Err(CrawlerError::paths_not_found(
566                path_clone,
567                self.source.clone(),
568                paths.iter().map(|s| s.as_ref().to_string()).collect(),
569            ));
570        };
571        path_clone.push(JsonPath::Pointer(path.as_ref().to_string()));
572        serde_json::from_value(found).map_err(|e| {
573            CrawlerError::parsing(
574                &path_clone,
575                self.source.clone(),
576                ParseTarget::Other(std::any::type_name::<T>().to_string()),
577                Some(format!("{e}")),
578            )
579        })
580    }
581    fn borrow_value<T: DeserializeOwned>(&self) -> CrawlerResult<T> {
582        T::deserialize(&self.crawler).map_err(|e| {
583            CrawlerError::parsing(
584                &self.path,
585                self.source.clone(),
586                ParseTarget::Other(std::any::type_name::<T>().to_string()),
587                Some(format!("{e}")),
588            )
589        })
590    }
591    fn borrow_value_pointer<T: DeserializeOwned>(&self, path: impl AsRef<str>) -> CrawlerResult<T> {
592        let mut path_clone = self.path.clone();
593        path_clone.push(JsonPath::pointer(path.as_ref()));
594        T::deserialize(
595            self.crawler
596                .pointer(path.as_ref())
597                .ok_or_else(|| CrawlerError::navigation(&path_clone, self.source.clone()))?,
598        )
599        .map_err(|e| {
600            CrawlerError::parsing(
601                &path_clone,
602                self.source.clone(),
603                ParseTarget::Other(std::any::type_name::<T>().to_string()),
604                Some(format!("{e}")),
605            )
606        })
607    }
608    fn path_exists(&self, path: &str) -> bool {
609        self.crawler.pointer(path).is_some()
610    }
611    fn get_source(&self) -> Arc<String> {
612        self.source.clone()
613    }
614    fn get_path(&self) -> String {
615        (&self.path).into()
616    }
617}
618
619#[derive(Clone, PartialEq, Debug)]
620pub enum JsonPath {
621    Pointer(String),
622    IndexNum(usize),
623}
624#[derive(Clone, Default, PartialEq, Debug)]
625struct PathList {
626    list: Vec<JsonPath>,
627}
628
629impl From<&JsonPath> for String {
630    fn from(value: &JsonPath) -> Self {
631        match value {
632            JsonPath::Pointer(p) => p.to_owned(),
633            JsonPath::IndexNum(i) => format! {"/{i}"},
634        }
635    }
636}
637impl JsonPath {
638    pub fn pointer<S: Into<String>>(path: S) -> Self {
639        JsonPath::Pointer(path.into())
640    }
641}
642impl PathList {
643    fn with(mut self, path: JsonPath) -> Self {
644        self.list.push(path);
645        self
646    }
647    fn push(&mut self, path: JsonPath) {
648        self.list.push(path)
649    }
650}
651
652// I believe both implementations are required, due to orphan rules.
653impl From<&PathList> for String {
654    fn from(value: &PathList) -> Self {
655        let mut path = String::new();
656        for p in &value.list {
657            path.push_str(String::from(p).as_str());
658        }
659        path
660    }
661}
662impl From<PathList> for String {
663    fn from(value: PathList) -> Self {
664        let mut path = String::new();
665        for p in &value.list {
666            path.push_str(String::from(p).as_str());
667        }
668        path
669    }
670}