reifydb-type 0.5.6

Core type system and value representations for ReifyDB
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 ReifyDB

use std::{
	cmp,
	cmp::Ordering,
	fmt,
	fmt::{Display, Formatter},
	ops::Deref,
	sync::Arc,
};

use serde::{Deserialize, Serialize};

#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct StatementColumn(pub u32);

impl Deref for StatementColumn {
	type Target = u32;

	fn deref(&self) -> &Self::Target {
		&self.0
	}
}

impl PartialEq<i32> for StatementColumn {
	fn eq(&self, other: &i32) -> bool {
		self.0 == *other as u32
	}
}

#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct StatementLine(pub u32);

impl Deref for StatementLine {
	type Target = u32;

	fn deref(&self) -> &Self::Target {
		&self.0
	}
}

impl PartialEq<i32> for StatementLine {
	fn eq(&self, other: &i32) -> bool {
		self.0 == *other as u32
	}
}

#[derive(Debug, Clone, PartialEq, Hash, Serialize, Deserialize, Default)]
pub enum Fragment {
	#[default]
	None,

	Statement {
		text: Arc<str>,
		line: StatementLine,
		column: StatementColumn,
	},

	Internal {
		text: Arc<str>,
	},
}

impl Fragment {
	pub fn text(&self) -> &str {
		match self {
			Fragment::None => "",
			Fragment::Statement {
				text,
				..
			}
			| Fragment::Internal {
				text,
				..
			} => text,
		}
	}

	pub fn line(&self) -> StatementLine {
		match self {
			Fragment::Statement {
				line,
				..
			} => *line,
			_ => StatementLine(1),
		}
	}

	pub fn column(&self) -> StatementColumn {
		match self {
			Fragment::Statement {
				column,
				..
			} => *column,
			_ => StatementColumn(0),
		}
	}

	pub fn sub_fragment(&self, offset: usize, length: usize) -> Fragment {
		let text = self.text();
		let end = cmp::min(offset + length, text.len());
		let sub_text = if offset < text.len() {
			&text[offset..end]
		} else {
			""
		};

		match self {
			Fragment::None => Fragment::None,
			Fragment::Statement {
				line,
				column,
				..
			} => Fragment::Statement {
				text: Arc::from(sub_text),
				line: *line,
				column: StatementColumn(column.0 + offset as u32),
			},
			Fragment::Internal {
				..
			} => Fragment::Internal {
				text: Arc::from(sub_text),
			},
		}
	}

	pub fn with_text(&self, text: impl AsRef<str>) -> Fragment {
		let text = Arc::from(text.as_ref());
		match self {
			Fragment::Statement {
				line,
				column,
				..
			} => Fragment::Statement {
				text,
				line: *line,
				column: *column,
			},
			Fragment::Internal {
				..
			} => Fragment::Internal {
				text,
			},
			Fragment::None => Fragment::Internal {
				text,
			},
		}
	}
}

impl Fragment {
	pub fn internal(text: impl AsRef<str>) -> Self {
		Fragment::Internal {
			text: Arc::from(text.as_ref()),
		}
	}

	pub fn testing(text: impl AsRef<str>) -> Self {
		Fragment::Statement {
			text: Arc::from(text.as_ref()),
			line: StatementLine(1),
			column: StatementColumn(0),
		}
	}

	pub fn testing_empty() -> Self {
		Self::testing("")
	}

	pub fn merge_all(fragments: impl IntoIterator<Item = Fragment>) -> Fragment {
		let mut fragments: Vec<Fragment> = fragments.into_iter().collect();
		assert!(!fragments.is_empty());

		fragments.sort();

		let first = fragments.first().unwrap();

		let mut text = String::with_capacity(fragments.iter().map(|f| f.text().len()).sum());
		for fragment in &fragments {
			text.push_str(fragment.text());
		}

		match first {
			Fragment::None => Fragment::None,
			Fragment::Statement {
				line,
				column,
				..
			} => Fragment::Statement {
				text: Arc::from(text),
				line: *line,
				column: *column,
			},
			Fragment::Internal {
				..
			} => Fragment::Internal {
				text: Arc::from(text),
			},
		}
	}

	pub fn fragment(&self) -> &str {
		self.text()
	}
}

impl AsRef<str> for Fragment {
	fn as_ref(&self) -> &str {
		self.text()
	}
}

impl Display for Fragment {
	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
		Display::fmt(self.text(), f)
	}
}

impl PartialOrd for Fragment {
	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
		Some(self.cmp(other))
	}
}

impl Ord for Fragment {
	fn cmp(&self, other: &Self) -> Ordering {
		self.column().cmp(&other.column()).then(self.line().cmp(&other.line()))
	}
}

impl Eq for Fragment {}

impl From<String> for Fragment {
	fn from(s: String) -> Self {
		Fragment::Internal {
			text: Arc::from(s),
		}
	}
}

impl From<&str> for Fragment {
	fn from(s: &str) -> Self {
		Fragment::Internal {
			text: Arc::from(s),
		}
	}
}

impl Fragment {
	pub fn statement(text: impl AsRef<str>, line: u32, column: u32) -> Self {
		Fragment::Statement {
			text: Arc::from(text.as_ref()),
			line: StatementLine(line),
			column: StatementColumn(column),
		}
	}

	pub fn none() -> Self {
		Fragment::None
	}
}

impl PartialEq<str> for Fragment {
	fn eq(&self, other: &str) -> bool {
		self.text() == other
	}
}

impl PartialEq<&str> for Fragment {
	fn eq(&self, other: &&str) -> bool {
		self.text() == *other
	}
}

impl PartialEq<String> for Fragment {
	fn eq(&self, other: &String) -> bool {
		self.text() == other.as_str()
	}
}

impl PartialEq<String> for &Fragment {
	fn eq(&self, other: &String) -> bool {
		self.text() == other.as_str()
	}
}

pub trait LazyFragment {
	fn fragment(&self) -> Fragment;
}

impl<F> LazyFragment for F
where
	F: Fn() -> Fragment,
{
	fn fragment(&self) -> Fragment {
		self()
	}
}

impl LazyFragment for &Fragment {
	fn fragment(&self) -> Fragment {
		(*self).clone()
	}
}

impl LazyFragment for Fragment {
	fn fragment(&self) -> Fragment {
		self.clone()
	}
}