use std::fmt;
use rowan::TextSize;
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{self, Visitor},
};
use crate::FileId;
#[derive(Eq, PartialEq, Hash, Debug, Clone, Copy)]
pub struct LuaDeclId {
pub file_id: FileId,
pub position: TextSize,
}
impl LuaDeclId {
pub fn new(file_id: FileId, position: TextSize) -> Self {
Self { file_id, position }
}
}
impl Serialize for LuaDeclId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let value = format!("{}|{}", self.file_id.id, u32::from(self.position));
serializer.serialize_str(&value)
}
}
impl<'de> Deserialize<'de> for LuaDeclId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct LuaDeclIdVisitor;
impl<'de> Visitor<'de> for LuaDeclIdVisitor {
type Value = LuaDeclId;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string with format 'file_id:position'")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let parts: Vec<&str> = value.split('|').collect();
if parts.len() != 2 {
return Err(E::custom("expected format 'file_id:position'"));
}
let file_id = FileId {
id: parts[0]
.parse()
.map_err(|e| E::custom(format!("invalid file_id: {}", e)))?,
};
let position = TextSize::new(
parts[1]
.parse()
.map_err(|e| E::custom(format!("invalid position: {}", e)))?,
);
Ok(LuaDeclId { file_id, position })
}
}
deserializer.deserialize_str(LuaDeclIdVisitor)
}
}