// ============================================================
// RDF 字面量 - RDF 1.1 语义
// ============================================================
///|
/// RDF 字面量
pub(all) struct Literal(LiteralContent) derive(Eq, Debug, Hash)
///|
/// IRI 引用
pub(all) struct NamedNodeRef {
iri : StringView
} derive(Debug, Eq, Hash)
///|
pub impl Show for NamedNodeRef with fn output(self, logger) {
logger.write(self.iri)
}
///|
/// IRI 节点 (拥有所有权)
pub(all) struct NamedNode {
iri : String
} derive(Debug, Eq, Hash, Default)
///|
pub impl Show for NamedNode with fn output(self, logger) {
logger.write(self.iri)
}
///|
/// 创建 NamedNodeRef (不验证)
pub fn NamedNode::new_unchecked(iri : StringView) -> NamedNodeRef {
NamedNodeRef::{ iri, }
}
///|
/// 转_owned
pub fn NamedNodeRef::into_owned(self : NamedNodeRef) -> NamedNode {
NamedNode::{ iri: self.iri.to_owned() }
}
///|
/// as_ref
pub fn NamedNode::as_ref(self : NamedNode) -> NamedNodeRef {
NamedNodeRef::{ iri: self.iri }
}
///|
pub impl Show for Literal with fn to_string(self) {
let f = StringBuilder::new()
match self.0 {
LiteralContent::String(value) => {
append_escaped_str(f, value)
f.to_string()
}
LiteralContent::LanguageTaggedString(value~, language~) => {
append_escaped_str(f, value)
f.write("@")
f.write(language)
f.to_string()
}
LiteralContent::DirectionalLanguageTaggedString(
value~,
language~,
direction~
) => {
append_escaped_str(f, value)
f.write("@")
f.write(language)
f.write("-")
f.write(direction)
f.to_string()
}
LiteralContent::TypedLiteral(value~, datatype~) => {
append_escaped_str(f, value)
f.write("^^")
f.write(datatype)
f.to_string()
}
}
}
///|
/// 字面量内容
pub(all) enum LiteralContent {
String(String) // 简单字符串
LanguageTaggedString(value~ : String, language~ : String) // 带语言标签
DirectionalLanguageTaggedString(
value~ : StringView,
language~ : String,
direction~ : BaseDirection
)
TypedLiteral(value~ : String, datatype~ : NamedNode) // 带类型
} derive(Eq, Debug, Hash)
///|
/// 创建简单字面量
pub fn Literal::new_simple_literal(value : String) -> Literal {
LiteralContent::String(value)
}
///|
/// 创建语言标签字面量 (验证语言标签)
pub fn Literal::new_language_tagged_literal(
value : String,
language : String,
) -> Result[Literal, TagParseErr] {
let language = String::to_lower(language)
match LanguageTag::parse(language) {
Ok(lang_tag) =>
Ok(
Literal::new_language_tagged_literal_unchecked(
value,
lang_tag.to_tagstr(),
),
)
Err(e) => Err(e)
}
}
///|
/// 创建语言标签字面量 (不验证)
pub fn Literal::new_language_tagged_literal_unchecked(
value : String,
language : String,
) -> Literal {
LiteralContent::LanguageTaggedString(value~, language~)
}
///|
/// 创建带方向的语言标签字面量 (验证语言标签)
pub fn Literal::new_directional_language_tagged_literal(
value : String,
language : String,
direction : BaseDirection,
) -> Result[Literal, TagParseErr] {
let language = String::to_lower(language)
match LanguageTag::parse(language) {
Ok(lang_tag) =>
Ok(
Literal::new_directional_language_tagged_literal_unchecked(
value, lang_tag, direction,
),
)
Err(e) => Err(e)
}
}
///|
/// 创建带方向的语言标签字面量 (不验证)
pub fn Literal::new_directional_language_tagged_literal_unchecked(
value : StringView,
language : LanguageTag,
direction : BaseDirection,
) -> Literal {
LiteralContent::DirectionalLanguageTaggedString(
value~,
language=language.to_tagstr(),
direction~,
)
}
///|
/// 获取字面量值
pub fn Literal::value(self : Literal) -> String {
match self.0 {
LiteralContent::String(value)
| LiteralContent::LanguageTaggedString(value~, ..) => value
LiteralContent::TypedLiteral(value~, ..) => value
LiteralContent::DirectionalLanguageTaggedString(value~, ..) =>
value.to_owned()
}
}
///|
/// 获取语言标签
pub fn Literal::language(self : Literal) -> String? {
match self.0 {
LiteralContent::LanguageTaggedString(language~, ..) => Some(language)
LiteralContent::DirectionalLanguageTaggedString(language~, ..) =>
Some(language)
_ => None
}
}
///|
/// 获取文本方向
pub fn Literal::direction(self : Literal) -> BaseDirection? {
match self.0 {
LiteralContent::DirectionalLanguageTaggedString(direction~, ..) =>
Some(direction)
_ => None
}
}
///|
/// 获取数据类型
pub fn Literal::datatype(self : Literal) -> NamedNodeRef {
match self.0 {
LiteralContent::LanguageTaggedString(..) => rdf_lang_string
LiteralContent::DirectionalLanguageTaggedString(..) => rdf_dir_lang_string
LiteralContent::String(_) => rdf_string
LiteralContent::TypedLiteral(datatype~, ..) => datatype.as_ref()
}
}
///|
/// 分解为 (值, 数据类型, 语言, 方向)
pub fn Literal::destruct(
self : Literal,
) -> (StringView, NamedNode?, String?, BaseDirection?) {
match self.0 {
LiteralContent::String(s) => (s, None, None, None)
LiteralContent::LanguageTaggedString(value~, language~) =>
(value, None, Some(language), None)
LiteralContent::DirectionalLanguageTaggedString(
value~,
language~,
direction~
) => (value, None, Some(language), Some(direction))
LiteralContent::TypedLiteral(value~, datatype~) =>
(value, Some(datatype), None, None)
}
}
///|
/// 字面量引用 (无所有权)
pub(all) struct LiteralRef(LiteralRefContent) derive(Eq, Debug, Hash)
///|
/// 字面量引用内容
pub(all) enum LiteralRefContent {
String(StringView)
LanguageTaggedString(value~ : String, language~ : StringView)
DirectionalLanguageTaggedString(
value~ : StringView,
language~ : StringView,
direction~ : BaseDirection
)
TypedLiteral(value~ : String, datatype~ : NamedNodeRef)
} derive(Eq, Debug, Hash)
///|
/// 获取字面量值
pub fn LiteralRef::as_value(self : LiteralRef) -> StringView {
match self.0 {
LiteralRefContent::String(s) => s
LiteralRefContent::LanguageTaggedString(value~, ..) => value
LiteralRefContent::DirectionalLanguageTaggedString(value~, ..) => value
LiteralRefContent::TypedLiteral(value~, ..) => value
}
}
///|
/// 创建简单字面量 (不验证)
pub fn Literal::new_simple_literal_unchecked(value : String) -> Literal {
Literal(LiteralContent::String(value))
}
///|
/// 创建类型字面量 (优化: string 直接用 String 类型)
pub fn Literal::new_typed_literal_unchecked(
value : String,
datatype : NamedNodeRef,
) -> LiteralRef {
LiteralRef(
if datatype == rdf_string {
LiteralRefContent::String(value)
} else {
LiteralRefContent::TypedLiteral(value~, datatype~)
},
)
}
///|
/// 获取数据类型
pub fn LiteralRef::datatype(self : LiteralRef) -> NamedNodeRef {
match self.0 {
LiteralRefContent::String(_) => rdf_string
LiteralRefContent::LanguageTaggedString(..) => rdf_lang_string
LiteralRefContent::DirectionalLanguageTaggedString(..) =>
rdf_dir_lang_string
LiteralRefContent::TypedLiteral(datatype~, ..) => datatype
}
}
///|
/// 转_owned
pub fn LiteralRef::into_owned(self : LiteralRef) -> Literal {
Literal(
match self.0 {
LiteralRefContent::String(value) =>
LiteralContent::String(value.to_owned())
LiteralRefContent::LanguageTaggedString(value~, language~) =>
LiteralContent::LanguageTaggedString(
value~,
language=language.to_owned(),
)
LiteralRefContent::DirectionalLanguageTaggedString(
value~,
language~,
direction~
) =>
LiteralContent::DirectionalLanguageTaggedString(
value=value.to_owned(),
language=language.to_owned(),
direction~,
)
LiteralRefContent::TypedLiteral(value~, datatype~) =>
LiteralContent::TypedLiteral(value~, datatype=datatype.into_owned())
},
)
}
///|
pub impl Show for LiteralRef with fn to_string(self) {
let f = StringBuilder::new()
match self.0 {
LiteralRefContent::String(value) => {
append_escaped_str(f, value)
f.to_string()
}
LiteralRefContent::LanguageTaggedString(value~, language~) => {
append_escaped_str(f, value)
f.write("@")
f.write(language)
f.to_string()
}
LiteralRefContent::DirectionalLanguageTaggedString(
value~,
language~,
direction~
) => {
append_escaped_str(f, value.to_owned())
f.write("@")
f.write(language)
f.write("^")
f.write(direction)
f.to_string()
}
LiteralRefContent::TypedLiteral(value~, datatype~) => {
append_escaped_str(f, value)
f.write("^^")
f.write(datatype)
f.to_string()
}
}
}
///|
/// 转义 N-Triples 特殊字符
pub fn append_escaped_str(f : StringBuilder, string : StringView) -> Unit {
for c in string {
let code = Char::to_uint(c)
match c {
'\u{08}' => f.write("\\b")
'\t' => f.write("\\t")
'\n' => f.write("\\n")
'\u{0C}' => f.write("\\f")
'\r' => f.write("\\r")
_ if code <= 0x1F || code >= 0x80 =>
f.write("\\u\{code.to_byte().to_hex().lpad(4, '0')}")
_ => f.write_char(c)
}
}
}
///|
/// 左侧填充
fn String::lpad(self : String, width : Int, char : Char) -> String {
let pad_count = width - self.length()
if pad_count <= 0 {
return self
}
String::make(pad_count, char) + self
}