change back to derive (de-)serialize for Span
This commit is contained in:
		
							parent
							
								
									2d2ecb5129
								
							
						
					
					
						commit
						179886e5e5
					
				| 
						 | 
					@ -43,3 +43,6 @@ strum = { version = "0.26.2", features = ["derive"] }
 | 
				
			||||||
strum_macros = "0.26.4"
 | 
					strum_macros = "0.26.4"
 | 
				
			||||||
thiserror = "2.0.11"
 | 
					thiserror = "2.0.11"
 | 
				
			||||||
tracing = "0.1.41"
 | 
					tracing = "0.1.41"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dev-dependencies]
 | 
				
			||||||
 | 
					serde_json = "1.0.138"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,6 +146,7 @@ impl SourceFile {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Represents a range of characters in a source file.
 | 
					/// Represents a range of characters in a source file.
 | 
				
			||||||
#[derive(Clone, Getters, CopyGetters)]
 | 
					#[derive(Clone, Getters, CopyGetters)]
 | 
				
			||||||
 | 
					#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 | 
				
			||||||
pub struct Span {
 | 
					pub struct Span {
 | 
				
			||||||
    /// Get the start byte index of the span.
 | 
					    /// Get the start byte index of the span.
 | 
				
			||||||
    #[get_copy = "pub"]
 | 
					    #[get_copy = "pub"]
 | 
				
			||||||
| 
						 | 
					@ -157,6 +158,7 @@ pub struct Span {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Get the source file that the span is located in.
 | 
					    /// Get the source file that the span is located in.
 | 
				
			||||||
    #[get = "pub"]
 | 
					    #[get = "pub"]
 | 
				
			||||||
 | 
					    #[cfg_attr(feature = "serde", serde(with = "crate::serde::source_file"))]
 | 
				
			||||||
    source_file: Arc<SourceFile>,
 | 
					    source_file: Arc<SourceFile>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ pub mod syntax;
 | 
				
			||||||
pub mod transpile;
 | 
					pub mod transpile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(feature = "serde")]
 | 
					#[cfg(feature = "serde")]
 | 
				
			||||||
mod serde;
 | 
					pub(crate) mod serde;
 | 
				
			||||||
#[cfg(feature = "serde")]
 | 
					#[cfg(feature = "serde")]
 | 
				
			||||||
#[cfg_attr(feature = "serde", doc(inline))]
 | 
					#[cfg_attr(feature = "serde", doc(inline))]
 | 
				
			||||||
pub use serde::SerdeWrapper;
 | 
					pub use serde::SerdeWrapper;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										223
									
								
								src/serde.rs
								
								
								
								
							
							
						
						
									
										223
									
								
								src/serde.rs
								
								
								
								
							| 
						 | 
					@ -12,7 +12,7 @@ use serde::{
 | 
				
			||||||
    Deserialize, Serialize,
 | 
					    Deserialize, Serialize,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::base::source_file::{SourceFile, Span};
 | 
					use crate::base::source_file::SourceFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DEDUPLICATE_SOURCE_FILES: LazyLock<RwLock<bool>> = LazyLock::new(|| RwLock::new(false));
 | 
					static DEDUPLICATE_SOURCE_FILES: LazyLock<RwLock<bool>> = LazyLock::new(|| RwLock::new(false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@ static DESERIALIZE_DATA: LazyLock<RwLock<Option<DeserializeData>>> =
 | 
				
			||||||
    LazyLock::new(|| RwLock::new(None));
 | 
					    LazyLock::new(|| RwLock::new(None));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Wrapper to remove duplicate source file data during (de-)serialization
 | 
					/// Wrapper to remove duplicate source file data during (de-)serialization
 | 
				
			||||||
 | 
					#[expect(clippy::module_name_repetitions)]
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct SerdeWrapper<T>(pub T);
 | 
					pub struct SerdeWrapper<T>(pub T);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,7 +84,7 @@ where
 | 
				
			||||||
            where
 | 
					            where
 | 
				
			||||||
                V: de::SeqAccess<'de>,
 | 
					                V: de::SeqAccess<'de>,
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                let source_files: BTreeMap<usize, SourceFile> = seq
 | 
					                let source_files: BTreeMap<u64, SourceFile> = seq
 | 
				
			||||||
                    .next_element()?
 | 
					                    .next_element()?
 | 
				
			||||||
                    .ok_or_else(|| de::Error::invalid_length(0, &self))?;
 | 
					                    .ok_or_else(|| de::Error::invalid_length(0, &self))?;
 | 
				
			||||||
                *DESERIALIZE_DATA.write().unwrap() = Some(DeserializeData {
 | 
					                *DESERIALIZE_DATA.write().unwrap() = Some(DeserializeData {
 | 
				
			||||||
| 
						 | 
					@ -103,7 +104,7 @@ where
 | 
				
			||||||
            where
 | 
					            where
 | 
				
			||||||
                V: de::MapAccess<'de>,
 | 
					                V: de::MapAccess<'de>,
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                let mut source_files: Option<BTreeMap<usize, SourceFile>> = None;
 | 
					                let mut source_files: Option<BTreeMap<u64, SourceFile>> = None;
 | 
				
			||||||
                let mut data = None;
 | 
					                let mut data = None;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                while let Some(key) = map.next_key()? {
 | 
					                while let Some(key) = map.next_key()? {
 | 
				
			||||||
| 
						 | 
					@ -140,7 +141,7 @@ where
 | 
				
			||||||
        let res = deserializer.deserialize_struct(
 | 
					        let res = deserializer.deserialize_struct(
 | 
				
			||||||
            "SerdeWrapper",
 | 
					            "SerdeWrapper",
 | 
				
			||||||
            &["source_files", "data"],
 | 
					            &["source_files", "data"],
 | 
				
			||||||
            WrapperVisitor(PhantomData::<T>::default()),
 | 
					            WrapperVisitor(PhantomData::<T>),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        *DEDUPLICATE_SOURCE_FILES.write().unwrap() = false;
 | 
					        *DEDUPLICATE_SOURCE_FILES.write().unwrap() = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -151,9 +152,9 @@ where
 | 
				
			||||||
/// Internally used for Serialization
 | 
					/// Internally used for Serialization
 | 
				
			||||||
#[derive(Debug, Default)]
 | 
					#[derive(Debug, Default)]
 | 
				
			||||||
struct SerializeData {
 | 
					struct SerializeData {
 | 
				
			||||||
    id_counter: usize,
 | 
					    id_counter: u64,
 | 
				
			||||||
    ptr_to_id: BTreeMap<usize, usize>,
 | 
					    ptr_to_id: BTreeMap<usize, u64>,
 | 
				
			||||||
    id_to_source_file: BTreeMap<usize, SourceFile>,
 | 
					    id_to_source_file: BTreeMap<u64, SourceFile>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl SerializeData {
 | 
					impl SerializeData {
 | 
				
			||||||
| 
						 | 
					@ -164,7 +165,7 @@ impl SerializeData {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Get id of already stored [`Arc`] or store it and return new id
 | 
					    /// Get id of already stored [`Arc`] or store it and return new id
 | 
				
			||||||
    pub fn get_id_of(&mut self, source_file: &Arc<SourceFile>) -> usize {
 | 
					    pub fn get_id_of(&mut self, source_file: &Arc<SourceFile>) -> u64 {
 | 
				
			||||||
        let ptr = Arc::as_ptr(source_file);
 | 
					        let ptr = Arc::as_ptr(source_file);
 | 
				
			||||||
        if let Some(&id) = self.ptr_to_id.get(&(ptr as usize)) {
 | 
					        if let Some(&id) = self.ptr_to_id.get(&(ptr as usize)) {
 | 
				
			||||||
            id
 | 
					            id
 | 
				
			||||||
| 
						 | 
					@ -181,150 +182,92 @@ impl SerializeData {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Serialize for Span {
 | 
					#[derive(Debug, Default)]
 | 
				
			||||||
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 | 
					struct DeserializeData {
 | 
				
			||||||
 | 
					    id_to_source_file: BTreeMap<u64, Arc<SourceFile>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod source_file {
 | 
				
			||||||
 | 
					    use std::sync::Arc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use serde::{de, Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use crate::{base::source_file::SourceFile, serde::DESERIALIZE_DATA};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use super::{DEDUPLICATE_SOURCE_FILES, SERIALIZE_DATA};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn serialize<S>(this: &Arc<SourceFile>, serializer: S) -> Result<S::Ok, S::Error>
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        S: serde::Serializer,
 | 
					        S: serde::Serializer,
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let mut s = serializer.serialize_struct("Span", 3)?;
 | 
					 | 
				
			||||||
        s.serialize_field("start", &self.start())?;
 | 
					 | 
				
			||||||
        s.serialize_field("end", &self.end())?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
 | 
					        if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
 | 
				
			||||||
            let mut data = SERIALIZE_DATA.lock().unwrap();
 | 
					            let mut data = SERIALIZE_DATA.lock().unwrap();
 | 
				
			||||||
            s.serialize_field("source_file", &data.get_id_of(self.source_file()))?;
 | 
					            serializer.serialize_u64(data.get_id_of(this))
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            s.serialize_field("source_file", self.source_file())?;
 | 
					            this.as_ref().serialize(serializer)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        s.end()
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Default)]
 | 
					    pub fn deserialize<'de, D>(deserializer: D) -> Result<Arc<SourceFile>, D::Error>
 | 
				
			||||||
struct DeserializeData {
 | 
					 | 
				
			||||||
    id_to_source_file: BTreeMap<usize, Arc<SourceFile>>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<'de> Deserialize<'de> for Span {
 | 
					 | 
				
			||||||
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
 | 
					 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        D: serde::Deserializer<'de>,
 | 
					        D: serde::Deserializer<'de>,
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        #[derive(Deserialize)]
 | 
					        if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
 | 
				
			||||||
        #[serde(field_identifier, rename_all = "snake_case")]
 | 
					            let id = u64::deserialize(deserializer)?;
 | 
				
			||||||
        enum Field {
 | 
					            Ok(DESERIALIZE_DATA
 | 
				
			||||||
            Start,
 | 
					                .read()
 | 
				
			||||||
            End,
 | 
					                .unwrap()
 | 
				
			||||||
            SourceFile,
 | 
					                .as_ref()
 | 
				
			||||||
 | 
					                .ok_or_else(|| de::Error::custom("SourceFiles do not have been loaded yet"))?
 | 
				
			||||||
 | 
					                .id_to_source_file
 | 
				
			||||||
 | 
					                .get(&id)
 | 
				
			||||||
 | 
					                .map(Arc::clone)
 | 
				
			||||||
 | 
					                .ok_or_else(|| serde::de::Error::custom("invalid source_file id"))?)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            Ok(Arc::new(SourceFile::deserialize(deserializer)?))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
        struct SpanVisitor;
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        impl<'de> Visitor<'de> for SpanVisitor {
 | 
					#[cfg(all(test, feature = "shulkerbox"))]
 | 
				
			||||||
            type Value = Span;
 | 
					mod tests {
 | 
				
			||||||
 | 
					    use std::path::Path;
 | 
				
			||||||
            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
 | 
					
 | 
				
			||||||
                if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
 | 
					    use shulkerbox::virtual_fs::{VFile, VFolder};
 | 
				
			||||||
                    formatter.write_str("struct Span with deduplicated SourceFiles")
 | 
					
 | 
				
			||||||
                } else {
 | 
					    use crate::{base::SilentHandler, syntax::syntax_tree::program::ProgramFile};
 | 
				
			||||||
                    formatter.write_str("struct Span")
 | 
					
 | 
				
			||||||
                }
 | 
					    use super::*;
 | 
				
			||||||
            }
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
            fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
 | 
					    fn test_serde_wrapper() {
 | 
				
			||||||
            where
 | 
					        let mut vfolder = VFolder::new();
 | 
				
			||||||
                V: serde::de::SeqAccess<'de>,
 | 
					        let vfile = VFile::Text(r#"namespace "test";"#.to_string());
 | 
				
			||||||
            {
 | 
					        vfolder.add_file("main.shu", vfile);
 | 
				
			||||||
                let start = seq
 | 
					
 | 
				
			||||||
                    .next_element()?
 | 
					        let parsed = crate::parse(
 | 
				
			||||||
                    .ok_or_else(|| de::Error::invalid_length(0, &self))?;
 | 
					            &SilentHandler::new(),
 | 
				
			||||||
                let end = seq
 | 
					            &vfolder,
 | 
				
			||||||
                    .next_element()?
 | 
					            Path::new("main.shu"),
 | 
				
			||||||
                    .ok_or_else(|| de::Error::invalid_length(1, &self))?;
 | 
					            "main".to_string(),
 | 
				
			||||||
                let source_file = if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
 | 
					        )
 | 
				
			||||||
                    DESERIALIZE_DATA
 | 
					        .unwrap();
 | 
				
			||||||
                        .read()
 | 
					
 | 
				
			||||||
                        .unwrap()
 | 
					        let wrapper = SerdeWrapper(parsed);
 | 
				
			||||||
                        .as_ref()
 | 
					
 | 
				
			||||||
                        .ok_or_else(|| {
 | 
					        let serialized = serde_json::to_string_pretty(&wrapper).unwrap();
 | 
				
			||||||
                            de::Error::custom("SourceFiles do not have been loaded yet")
 | 
					        let SerdeWrapper(deserialized) =
 | 
				
			||||||
                        })?
 | 
					            serde_json::from_str::<SerdeWrapper<ProgramFile>>(&serialized).unwrap();
 | 
				
			||||||
                        .id_to_source_file
 | 
					
 | 
				
			||||||
                        .get(
 | 
					        assert_eq!(
 | 
				
			||||||
                            &seq.next_element()?
 | 
					            Arc::as_ptr(
 | 
				
			||||||
                                .ok_or_else(|| de::Error::invalid_length(2, &self))?,
 | 
					                deserialized
 | 
				
			||||||
                        )
 | 
					                    .namespace()
 | 
				
			||||||
                        .ok_or_else(|| de::Error::custom("invalid source_file id"))?
 | 
					                    .namespace_keyword()
 | 
				
			||||||
                        .clone()
 | 
					                    .span
 | 
				
			||||||
                } else {
 | 
					                    .source_file()
 | 
				
			||||||
                    Arc::new(
 | 
					            ),
 | 
				
			||||||
                        seq.next_element()?
 | 
					            Arc::as_ptr(deserialized.namespace().namespace_name().span.source_file())
 | 
				
			||||||
                            .ok_or_else(|| de::Error::invalid_length(2, &self))?,
 | 
					        );
 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                Ok(Span::new(source_file, start, end)
 | 
					 | 
				
			||||||
                    .ok_or_else(|| de::Error::custom("Invalid data"))?)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
 | 
					 | 
				
			||||||
            where
 | 
					 | 
				
			||||||
                V: de::MapAccess<'de>,
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                let mut start = None;
 | 
					 | 
				
			||||||
                let mut end = None;
 | 
					 | 
				
			||||||
                let mut source_file = None;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                while let Some(key) = map.next_key()? {
 | 
					 | 
				
			||||||
                    match key {
 | 
					 | 
				
			||||||
                        Field::Start => {
 | 
					 | 
				
			||||||
                            if start.is_some() {
 | 
					 | 
				
			||||||
                                return Err(de::Error::duplicate_field("start"));
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            start = Some(map.next_value()?);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        Field::End => {
 | 
					 | 
				
			||||||
                            if end.is_some() {
 | 
					 | 
				
			||||||
                                return Err(de::Error::duplicate_field("end"));
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            end = Some(map.next_value()?);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        Field::SourceFile => {
 | 
					 | 
				
			||||||
                            if source_file.is_some() {
 | 
					 | 
				
			||||||
                                return Err(de::Error::duplicate_field("source_file"));
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            source_file = if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
 | 
					 | 
				
			||||||
                                Some(
 | 
					 | 
				
			||||||
                                    DESERIALIZE_DATA
 | 
					 | 
				
			||||||
                                        .read()
 | 
					 | 
				
			||||||
                                        .unwrap()
 | 
					 | 
				
			||||||
                                        .as_ref()
 | 
					 | 
				
			||||||
                                        .ok_or_else(|| {
 | 
					 | 
				
			||||||
                                            de::Error::custom(
 | 
					 | 
				
			||||||
                                                "SourceFiles do not have been loaded yet",
 | 
					 | 
				
			||||||
                                            )
 | 
					 | 
				
			||||||
                                        })?
 | 
					 | 
				
			||||||
                                        .id_to_source_file
 | 
					 | 
				
			||||||
                                        .get(&map.next_value()?)
 | 
					 | 
				
			||||||
                                        .ok_or_else(|| de::Error::custom("invalid source_file id"))?
 | 
					 | 
				
			||||||
                                        .clone(),
 | 
					 | 
				
			||||||
                                )
 | 
					 | 
				
			||||||
                            } else {
 | 
					 | 
				
			||||||
                                Some(Arc::new(map.next_value()?))
 | 
					 | 
				
			||||||
                            };
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                let start = start.ok_or_else(|| de::Error::missing_field("start"))?;
 | 
					 | 
				
			||||||
                let end = end.ok_or_else(|| de::Error::missing_field("end"))?;
 | 
					 | 
				
			||||||
                let source_file = source_file.ok_or_else(|| de::Error::missing_field("source"))?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                Ok(Span::new(source_file, start, end)
 | 
					 | 
				
			||||||
                    .ok_or_else(|| de::Error::custom("Invalid data"))?)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        deserializer.deserialize_struct("Span", &["start", "end", "source_file"], SpanVisitor)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue