execute_evcxr/
evcxr_source.rs1use std::{
2 hash::{Hash, Hasher},
3 ops::Deref,
4 str::from_utf8_unchecked,
5};
6use syn::parse_str;
7
8use crate::{ParsedEvcxr, ScriptlikeRust};
9
10pub(crate) struct EvcxrSource<S>(pub S)
11where
12 S: AsRef<str>;
13
14impl<'a,S> From<S> for EvcxrSource<S>
15where
16 S: AsRef<str>
17{
18 fn from(s: S) -> Self {
19 EvcxrSource(s)
20 }
21}
22
23impl<'a, S> EvcxrSource<S>
24where
25 S: AsRef<str>
26{
27 pub(crate) fn parse(&self) -> syn::Result<ParsedEvcxr> {
28 let mut hasher = std::collections::hash_map::DefaultHasher::new();
29 self.0.as_ref().hash(&mut hasher);
30 let hash = hasher.finish();
31
32 let mut prefixed_dependencies = Vec::<&str>::with_capacity(255);
33 for dep in self
34 .0
35 .as_ref()
36 .lines()
37 .map(|line| line.trim())
38 .filter(|line| line.starts_with(":dep"))
39 {
40 prefixed_dependencies.push(dep);
41 }
42 let scriptlike_rust = match prefixed_dependencies.last().map(Deref::deref) {
43 None => self.0.as_ref(),
44 Some(line) => {
45 let src_ptr = self.0.as_ref().as_ptr();
46 let src_len = self.0.as_ref().len();
47 let line_ptr = line.as_ptr();
48 let line_len = line.len();
49 let src_to_line_offset = unsafe { line_ptr.offset_from(src_ptr) };
52 debug_assert!(src_to_line_offset >= 0);
53 let scriptlike_rust_ptr =
54 unsafe { src_ptr.offset(src_to_line_offset + line_len as isize) };
55 let scriptlike_rust_len = src_len - src_to_line_offset as usize - line_len;
56 unsafe {
57 from_utf8_unchecked(std::slice::from_raw_parts(
58 scriptlike_rust_ptr,
59 scriptlike_rust_len,
60 ))
61 }
62 .trim()
63 }
64 };
65 let scriptlike_rust: ScriptlikeRust = parse_str(scriptlike_rust)?;
66 Ok(ParsedEvcxr {
67 prefixed_dependencies,
68 scriptlike_rust,
69 hash,
70 })
71 }
72}