1use std::any::{Any, TypeId};
11use std::cell::RefCell;
12use std::collections::{BTreeMap, BTreeSet};
13use std::error::Error;
14use std::fmt;
15use std::rc::Rc;
16use std::str::FromStr;
17use std::sync::Arc;
18
19use crate::link_network::{Link, LinkId, LinkMetadata, LinkNetwork, LinkType};
20
21const TYPE_TERM_PREFIX: &str = "rust::type::";
22const LITERAL_TERM_PREFIX: &str = "rust::literal::";
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
26pub enum RustTypeKind {
27 Primitive,
28 Struct,
29 Enum,
30 Trait,
31 Sequence,
32 Option,
33 Map,
34}
35
36impl RustTypeKind {
37 const fn as_str(self) -> &'static str {
38 match self {
39 Self::Primitive => "primitive",
40 Self::Struct => "struct",
41 Self::Enum => "enum",
42 Self::Trait => "trait",
43 Self::Sequence => "sequence",
44 Self::Option => "option",
45 Self::Map => "map",
46 }
47 }
48}
49
50impl fmt::Display for RustTypeKind {
51 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
52 formatter.write_str(self.as_str())
53 }
54}
55
56#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
58pub struct RustFieldShape {
59 name: String,
60 type_name: String,
61}
62
63impl RustFieldShape {
64 #[must_use]
66 pub fn new(name: impl Into<String>, type_name: impl Into<String>) -> Self {
67 Self {
68 name: name.into(),
69 type_name: type_name.into(),
70 }
71 }
72
73 #[must_use]
75 pub fn name(&self) -> &str {
76 &self.name
77 }
78
79 #[must_use]
81 pub fn type_name(&self) -> &str {
82 &self.type_name
83 }
84}
85
86#[derive(Clone, Debug, PartialEq, Eq)]
88pub struct RustTypeShape {
89 name: String,
90 kind: RustTypeKind,
91 fields: Vec<RustFieldShape>,
92}
93
94impl RustTypeShape {
95 #[must_use]
97 pub fn primitive(name: impl Into<String>) -> Self {
98 Self {
99 name: name.into(),
100 kind: RustTypeKind::Primitive,
101 fields: Vec::new(),
102 }
103 }
104
105 #[must_use]
107 pub fn structure<I>(name: impl Into<String>, fields: I) -> Self
108 where
109 I: IntoIterator<Item = RustFieldShape>,
110 {
111 Self {
112 name: name.into(),
113 kind: RustTypeKind::Struct,
114 fields: fields.into_iter().collect(),
115 }
116 }
117
118 #[must_use]
120 pub fn enumeration<I>(name: impl Into<String>, variants: I) -> Self
121 where
122 I: IntoIterator<Item = RustFieldShape>,
123 {
124 Self {
125 name: name.into(),
126 kind: RustTypeKind::Enum,
127 fields: variants.into_iter().collect(),
128 }
129 }
130
131 #[must_use]
133 pub fn trait_type<I>(name: impl Into<String>, items: I) -> Self
134 where
135 I: IntoIterator<Item = RustFieldShape>,
136 {
137 Self {
138 name: name.into(),
139 kind: RustTypeKind::Trait,
140 fields: items.into_iter().collect(),
141 }
142 }
143
144 #[must_use]
146 pub fn sequence(name: impl Into<String>, element_type: impl Into<String>) -> Self {
147 Self {
148 name: name.into(),
149 kind: RustTypeKind::Sequence,
150 fields: vec![RustFieldShape::new("item", element_type)],
151 }
152 }
153
154 #[must_use]
156 pub fn option(name: impl Into<String>, value_type: impl Into<String>) -> Self {
157 Self {
158 name: name.into(),
159 kind: RustTypeKind::Option,
160 fields: vec![
161 RustFieldShape::new("Some", value_type),
162 RustFieldShape::new("None", "()"),
163 ],
164 }
165 }
166
167 #[must_use]
169 pub fn map(
170 name: impl Into<String>,
171 key_type: impl Into<String>,
172 value_type: impl Into<String>,
173 ) -> Self {
174 Self {
175 name: name.into(),
176 kind: RustTypeKind::Map,
177 fields: vec![
178 RustFieldShape::new("entry", "BTreeMapEntry"),
179 RustFieldShape::new("key", key_type),
180 RustFieldShape::new("value", value_type),
181 ],
182 }
183 }
184
185 #[must_use]
187 pub fn name(&self) -> &str {
188 &self.name
189 }
190
191 #[must_use]
193 pub const fn kind(&self) -> RustTypeKind {
194 self.kind
195 }
196
197 #[must_use]
199 pub fn fields(&self) -> &[RustFieldShape] {
200 &self.fields
201 }
202}
203
204#[derive(Clone, Debug, PartialEq, Eq)]
206pub enum LinksCodecError {
207 MissingLink(LinkId),
209 ExpectedObject { link: LinkId },
211 MalformedObject { object: LinkId, reason: String },
213 UnexpectedType {
215 object: LinkId,
216 expected: String,
217 actual: Option<String>,
218 },
219 MissingField { object: LinkId, field: String },
221 DuplicateField { object: LinkId, field: String },
223 MalformedField { field: LinkId, reason: String },
225 InvalidLiteral {
227 object: LinkId,
228 type_name: String,
229 value: Option<String>,
230 reason: String,
231 },
232 CacheTypeMismatch { type_name: String },
234}
235
236impl fmt::Display for LinksCodecError {
237 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
238 match self {
239 Self::MissingLink(link) => write!(formatter, "missing link {link}"),
240 Self::ExpectedObject { link } => write!(formatter, "link {link} is not an object"),
241 Self::MalformedObject { object, reason } => {
242 write!(formatter, "object {object} is malformed: {reason}")
243 }
244 Self::UnexpectedType {
245 object,
246 expected,
247 actual,
248 } => write!(
249 formatter,
250 "object {object} has type {:?}, expected {expected:?}",
251 actual.as_deref()
252 ),
253 Self::MissingField { object, field } => {
254 write!(formatter, "object {object} is missing field {field:?}")
255 }
256 Self::DuplicateField { object, field } => {
257 write!(formatter, "object {object} has multiple {field:?} fields")
258 }
259 Self::MalformedField { field, reason } => {
260 write!(formatter, "field link {field} is malformed: {reason}")
261 }
262 Self::InvalidLiteral {
263 object,
264 type_name,
265 value,
266 reason,
267 } => write!(
268 formatter,
269 "object {object} has invalid {type_name} literal {:?}: {reason}",
270 value.as_deref()
271 ),
272 Self::CacheTypeMismatch { type_name } => {
273 write!(
274 formatter,
275 "cached object was not an Rc<RefCell<{type_name}>>"
276 )
277 }
278 }
279 }
280}
281
282impl Error for LinksCodecError {}
283
284pub trait ToLinks {
286 fn to_links(&self, encoder: &mut LinksEncoder) -> LinkId;
288}
289
290pub trait FromLinks: Sized {
292 fn from_links(decoder: &mut LinksDecoder<'_>, link: LinkId) -> Result<Self, LinksCodecError>;
294}
295
296pub trait LinksObject: Default + 'static {
303 const TYPE_NAME: &'static str;
305
306 fn type_shape() -> RustTypeShape;
308
309 fn encode_fields(&self, encoder: &mut LinksEncoder, object: LinkId);
311
312 fn decode_fields(
314 &mut self,
315 decoder: &mut LinksDecoder<'_>,
316 object: LinkId,
317 ) -> Result<(), LinksCodecError>;
318}
319
320impl LinkNetwork {
321 pub fn insert_object_instance(&mut self, type_id: LinkId) -> LinkId {
327 let id = LinkId(self.next_id);
328 self.next_id += 1;
329 self.links.insert(
330 id,
331 Arc::new(Link {
332 id,
333 references: Arc::from(vec![id, type_id]),
334 metadata: LinkMetadata::new().with_link_type(LinkType::Object),
335 }),
336 );
337 id
338 }
339}
340
341#[derive(Debug)]
343pub struct LinksEncoder {
344 network: LinkNetwork,
345 object_cache: BTreeMap<usize, LinkId>,
346 registered_shapes: BTreeSet<String>,
347}
348
349impl Default for LinksEncoder {
350 fn default() -> Self {
351 Self::new()
352 }
353}
354
355impl LinksEncoder {
356 #[must_use]
358 pub fn new() -> Self {
359 Self {
360 network: LinkNetwork::self_describing(),
361 object_cache: BTreeMap::new(),
362 registered_shapes: BTreeSet::new(),
363 }
364 }
365
366 #[must_use]
368 pub const fn with_network(network: LinkNetwork) -> Self {
369 Self {
370 network,
371 object_cache: BTreeMap::new(),
372 registered_shapes: BTreeSet::new(),
373 }
374 }
375
376 #[must_use]
378 pub const fn network(&self) -> &LinkNetwork {
379 &self.network
380 }
381
382 pub fn network_mut(&mut self) -> &mut LinkNetwork {
384 &mut self.network
385 }
386
387 #[must_use]
389 pub fn into_network(self) -> LinkNetwork {
390 self.network
391 }
392
393 pub fn encode<T: ToLinks + ?Sized>(&mut self, value: &T) -> LinkId {
395 value.to_links(self)
396 }
397
398 pub fn register_type_shape(&mut self, shape: &RustTypeShape) -> LinkId {
400 let shape_type_term = type_term(shape.name());
401 let definition = format!("Rust {} type {}", shape.kind(), shape.name());
402 let type_id =
403 self.network
404 .insert_typed_point(&shape_type_term, LinkType::Type, Some(&definition));
405
406 if !self.registered_shapes.insert(shape.name().to_string()) {
407 return type_id;
408 }
409
410 let kind = self.network.insert_typed_point(
411 &format!("rust::type-kind::{}", shape.kind()),
412 LinkType::Concept,
413 None,
414 );
415 self.network.insert_dynamic_link(
416 &[type_id, kind],
417 LinkMetadata::new().with_link_type(LinkType::Relation),
418 );
419
420 for field in shape.fields() {
421 let field_type_id = self.network.insert_typed_point(
422 &type_term(field.type_name()),
423 LinkType::Type,
424 Some(&format!("Rust referenced type {}", field.type_name())),
425 );
426 self.network
427 .insert_field(type_id, field.name(), field_type_id);
428 }
429
430 type_id
431 }
432
433 pub fn begin_object(&mut self, shape: &RustTypeShape) -> LinkId {
435 let type_id = self.register_type_shape(shape);
436 self.network.insert_object_instance(type_id)
437 }
438
439 pub fn encode_field<T: ToLinks + ?Sized>(
441 &mut self,
442 object: LinkId,
443 name: &str,
444 value: &T,
445 ) -> LinkId {
446 let value = value.to_links(self);
447 self.network.insert_field(object, name, value)
448 }
449
450 fn encode_literal(&mut self, type_name: &str, value: &str) -> LinkId {
451 let object = self.begin_object(&RustTypeShape::primitive(type_name));
452 let literal = self.network.insert_typed_point(
453 &literal_term(type_name, value),
454 LinkType::Concept,
455 None,
456 );
457 self.network.insert_field(object, "value", literal);
458 object
459 }
460
461 fn encode_rc<T: LinksObject>(&mut self, value: &Rc<RefCell<T>>) -> LinkId {
462 let key = Rc::as_ptr(value).cast::<()>() as usize;
463 if let Some(existing) = self.object_cache.get(&key) {
464 return *existing;
465 }
466
467 let object = self.begin_object(&T::type_shape());
468 self.object_cache.insert(key, object);
469 value.borrow().encode_fields(self, object);
470 object
471 }
472}
473
474#[derive(Debug)]
476pub struct LinksDecoder<'network> {
477 network: &'network LinkNetwork,
478 object_cache: BTreeMap<(TypeId, LinkId), Box<dyn Any>>,
479}
480
481impl<'network> LinksDecoder<'network> {
482 #[must_use]
484 pub fn new(network: &'network LinkNetwork) -> Self {
485 Self {
486 network,
487 object_cache: BTreeMap::new(),
488 }
489 }
490
491 #[must_use]
493 pub const fn network(&self) -> &'network LinkNetwork {
494 self.network
495 }
496
497 pub fn decode<T: FromLinks>(&mut self, link: LinkId) -> Result<T, LinksCodecError> {
499 T::from_links(self, link)
500 }
501
502 pub fn decode_field<T: FromLinks>(
504 &mut self,
505 object: LinkId,
506 field: &str,
507 ) -> Result<T, LinksCodecError> {
508 let value = self.field_value(object, field)?;
509 T::from_links(self, value)
510 }
511
512 fn decode_field_values<T: FromLinks>(
513 &mut self,
514 object: LinkId,
515 field: &str,
516 ) -> Result<Vec<T>, LinksCodecError> {
517 let values = self.field_values(object, field)?;
518 values
519 .into_iter()
520 .map(|value| T::from_links(self, value))
521 .collect()
522 }
523
524 fn decode_rc<T: LinksObject>(
525 &mut self,
526 object: LinkId,
527 ) -> Result<Rc<RefCell<T>>, LinksCodecError> {
528 let key = (TypeId::of::<T>(), object);
529 if let Some(cached) = self.object_cache.get(&key) {
530 let typed = cached.downcast_ref::<Rc<RefCell<T>>>().ok_or_else(|| {
531 LinksCodecError::CacheTypeMismatch {
532 type_name: T::TYPE_NAME.to_string(),
533 }
534 })?;
535 return Ok(Rc::clone(typed));
536 }
537
538 self.expect_object_type(object, T::TYPE_NAME)?;
539 let decoded = Rc::new(RefCell::new(T::default()));
540 self.object_cache.insert(key, Box::new(Rc::clone(&decoded)));
541 decoded.borrow_mut().decode_fields(self, object)?;
542 Ok(decoded)
543 }
544
545 fn expect_object_type(&self, object: LinkId, expected: &str) -> Result<(), LinksCodecError> {
546 let actual = self.object_type_name(object)?;
547 if actual.as_deref() == Some(expected) {
548 return Ok(());
549 }
550
551 Err(LinksCodecError::UnexpectedType {
552 object,
553 expected: expected.to_string(),
554 actual,
555 })
556 }
557
558 fn object_type_name(&self, object: LinkId) -> Result<Option<String>, LinksCodecError> {
559 let link = self
560 .network
561 .link(object)
562 .ok_or(LinksCodecError::MissingLink(object))?;
563 if link.metadata().link_type() != Some(LinkType::Object) {
564 return Err(LinksCodecError::ExpectedObject { link: object });
565 }
566 let references = link.references();
567 if references.first() != Some(&object) {
568 return Err(LinksCodecError::MalformedObject {
569 object,
570 reason: "first reference must preserve object identity".to_string(),
571 });
572 }
573 let type_id = references
574 .get(1)
575 .ok_or_else(|| LinksCodecError::MalformedObject {
576 object,
577 reason: "second reference must point to a type shape".to_string(),
578 })?;
579 let type_link = self
580 .network
581 .link(*type_id)
582 .ok_or(LinksCodecError::MissingLink(*type_id))?;
583 Ok(type_link
584 .metadata()
585 .term()
586 .and_then(|term| term.strip_prefix(TYPE_TERM_PREFIX))
587 .map(ToString::to_string))
588 }
589
590 fn field_value(&self, object: LinkId, field: &str) -> Result<LinkId, LinksCodecError> {
591 let values = self.field_values(object, field)?;
592 match values.as_slice() {
593 [value] => Ok(*value),
594 [] => Err(LinksCodecError::MissingField {
595 object,
596 field: field.to_string(),
597 }),
598 _ => Err(LinksCodecError::DuplicateField {
599 object,
600 field: field.to_string(),
601 }),
602 }
603 }
604
605 fn field_values(&self, object: LinkId, field: &str) -> Result<Vec<LinkId>, LinksCodecError> {
606 if self.network.link(object).is_none() {
607 return Err(LinksCodecError::MissingLink(object));
608 }
609
610 let mut values = Vec::new();
611 for link in self
612 .network
613 .links()
614 .filter(|link| link.metadata().link_type() == Some(LinkType::Field))
615 {
616 let references = link.references();
617 if references.first() != Some(&object) {
618 continue;
619 }
620 let [_, label, value] = references else {
621 return Err(LinksCodecError::MalformedField {
622 field: link.id(),
623 reason: "field links must have parent, label, and child references".to_string(),
624 });
625 };
626 let Some(label_term) = self
627 .network
628 .link(*label)
629 .ok_or(LinksCodecError::MissingLink(*label))?
630 .metadata()
631 .term()
632 else {
633 continue;
634 };
635 if label_term == field {
636 values.push(*value);
637 }
638 }
639 Ok(values)
640 }
641
642 fn decode_literal(&self, object: LinkId, type_name: &str) -> Result<String, LinksCodecError> {
643 self.expect_object_type(object, type_name)?;
644 let literal = self.field_value(object, "value")?;
645 let term = self
646 .network
647 .link(literal)
648 .ok_or(LinksCodecError::MissingLink(literal))?
649 .metadata()
650 .term()
651 .map(ToString::to_string);
652 let Some(term) = term else {
653 return Err(LinksCodecError::InvalidLiteral {
654 object,
655 type_name: type_name.to_string(),
656 value: None,
657 reason: "literal link has no term".to_string(),
658 });
659 };
660 let prefix = literal_prefix(type_name);
661 term.strip_prefix(&prefix)
662 .map(ToString::to_string)
663 .ok_or_else(|| LinksCodecError::InvalidLiteral {
664 object,
665 type_name: type_name.to_string(),
666 value: Some(term),
667 reason: "literal term has the wrong prefix".to_string(),
668 })
669 }
670}
671
672impl<T: LinksObject> ToLinks for Rc<RefCell<T>> {
673 fn to_links(&self, encoder: &mut LinksEncoder) -> LinkId {
674 encoder.encode_rc(self)
675 }
676}
677
678impl<T: LinksObject> FromLinks for Rc<RefCell<T>> {
679 fn from_links(decoder: &mut LinksDecoder<'_>, link: LinkId) -> Result<Self, LinksCodecError> {
680 decoder.decode_rc(link)
681 }
682}
683
684impl<T: ToLinks> ToLinks for Option<T> {
685 fn to_links(&self, encoder: &mut LinksEncoder) -> LinkId {
686 let object = encoder.begin_object(&RustTypeShape::option("Option", "T"));
687 match self {
688 Some(value) => {
689 encoder.encode_field(object, "Some", value);
690 }
691 None => {
692 encoder.encode_field(object, "None", &());
693 }
694 }
695 object
696 }
697}
698
699impl<T: FromLinks> FromLinks for Option<T> {
700 fn from_links(decoder: &mut LinksDecoder<'_>, link: LinkId) -> Result<Self, LinksCodecError> {
701 decoder.expect_object_type(link, "Option")?;
702 let some = decoder.field_values(link, "Some")?;
703 let none = decoder.field_values(link, "None")?;
704 match (some.as_slice(), none.as_slice()) {
705 ([value], []) => T::from_links(decoder, *value).map(Some),
706 ([], [_]) => Ok(None),
707 ([], []) => Err(LinksCodecError::MissingField {
708 object: link,
709 field: "Some/None".to_string(),
710 }),
711 _ => Err(LinksCodecError::MalformedObject {
712 object: link,
713 reason: "Option must contain exactly one Some or None variant".to_string(),
714 }),
715 }
716 }
717}
718
719impl<T: ToLinks> ToLinks for Vec<T> {
720 fn to_links(&self, encoder: &mut LinksEncoder) -> LinkId {
721 let object = encoder.begin_object(&RustTypeShape::sequence("Vec", "T"));
722 for item in self {
723 encoder.encode_field(object, "item", item);
724 }
725 object
726 }
727}
728
729impl<T: FromLinks> FromLinks for Vec<T> {
730 fn from_links(decoder: &mut LinksDecoder<'_>, link: LinkId) -> Result<Self, LinksCodecError> {
731 decoder.expect_object_type(link, "Vec")?;
732 decoder.decode_field_values(link, "item")
733 }
734}
735
736impl<K, V> ToLinks for BTreeMap<K, V>
737where
738 K: ToLinks,
739 V: ToLinks,
740{
741 fn to_links(&self, encoder: &mut LinksEncoder) -> LinkId {
742 let object = encoder.begin_object(&RustTypeShape::map("BTreeMap", "K", "V"));
743 for (key, value) in self {
744 let entry = encoder.begin_object(&RustTypeShape::structure(
745 "BTreeMapEntry",
746 [
747 RustFieldShape::new("key", "K"),
748 RustFieldShape::new("value", "V"),
749 ],
750 ));
751 encoder.encode_field(entry, "key", key);
752 encoder.encode_field(entry, "value", value);
753 encoder.network.insert_field(object, "entry", entry);
754 }
755 object
756 }
757}
758
759impl<K, V> FromLinks for BTreeMap<K, V>
760where
761 K: FromLinks + Ord,
762 V: FromLinks,
763{
764 fn from_links(decoder: &mut LinksDecoder<'_>, link: LinkId) -> Result<Self, LinksCodecError> {
765 decoder.expect_object_type(link, "BTreeMap")?;
766 let mut map = Self::new();
767 for entry in decoder.field_values(link, "entry")? {
768 decoder.expect_object_type(entry, "BTreeMapEntry")?;
769 let key = decoder.decode_field(entry, "key")?;
770 let value = decoder.decode_field(entry, "value")?;
771 map.insert(key, value);
772 }
773 Ok(map)
774 }
775}
776
777impl ToLinks for () {
778 fn to_links(&self, encoder: &mut LinksEncoder) -> LinkId {
779 encoder.encode_literal("()", "unit")
780 }
781}
782
783impl FromLinks for () {
784 fn from_links(decoder: &mut LinksDecoder<'_>, link: LinkId) -> Result<Self, LinksCodecError> {
785 let _ = decoder.decode_literal(link, "()")?;
786 Ok(())
787 }
788}
789
790impl ToLinks for String {
791 fn to_links(&self, encoder: &mut LinksEncoder) -> LinkId {
792 encoder.encode_literal("String", self)
793 }
794}
795
796impl ToLinks for str {
797 fn to_links(&self, encoder: &mut LinksEncoder) -> LinkId {
798 encoder.encode_literal("String", self)
799 }
800}
801
802impl FromLinks for String {
803 fn from_links(decoder: &mut LinksDecoder<'_>, link: LinkId) -> Result<Self, LinksCodecError> {
804 decoder.decode_literal(link, "String")
805 }
806}
807
808impl ToLinks for char {
809 fn to_links(&self, encoder: &mut LinksEncoder) -> LinkId {
810 encoder.encode_literal("char", &self.to_string())
811 }
812}
813
814impl FromLinks for char {
815 fn from_links(decoder: &mut LinksDecoder<'_>, link: LinkId) -> Result<Self, LinksCodecError> {
816 let value = decoder.decode_literal(link, "char")?;
817 let mut chars = value.chars();
818 let Some(character) = chars.next() else {
819 return Err(invalid_literal(
820 link,
821 "char",
822 Some(value),
823 "literal is empty",
824 ));
825 };
826 if chars.next().is_some() {
827 return Err(invalid_literal(
828 link,
829 "char",
830 Some(value),
831 "literal contains more than one character",
832 ));
833 }
834 Ok(character)
835 }
836}
837
838macro_rules! impl_fromstr_literal_codec {
839 ($type:ty, $name:literal) => {
840 impl ToLinks for $type {
841 fn to_links(&self, encoder: &mut LinksEncoder) -> LinkId {
842 encoder.encode_literal($name, &self.to_string())
843 }
844 }
845
846 impl FromLinks for $type {
847 fn from_links(
848 decoder: &mut LinksDecoder<'_>,
849 link: LinkId,
850 ) -> Result<Self, LinksCodecError> {
851 let value = decoder.decode_literal(link, $name)?;
852 <$type>::from_str(&value)
853 .map_err(|error| invalid_literal(link, $name, Some(value), &error.to_string()))
854 }
855 }
856 };
857}
858
859impl_fromstr_literal_codec!(bool, "bool");
860impl_fromstr_literal_codec!(i8, "i8");
861impl_fromstr_literal_codec!(i16, "i16");
862impl_fromstr_literal_codec!(i32, "i32");
863impl_fromstr_literal_codec!(i64, "i64");
864impl_fromstr_literal_codec!(i128, "i128");
865impl_fromstr_literal_codec!(isize, "isize");
866impl_fromstr_literal_codec!(u8, "u8");
867impl_fromstr_literal_codec!(u16, "u16");
868impl_fromstr_literal_codec!(u32, "u32");
869impl_fromstr_literal_codec!(u64, "u64");
870impl_fromstr_literal_codec!(u128, "u128");
871impl_fromstr_literal_codec!(usize, "usize");
872impl_fromstr_literal_codec!(f32, "f32");
873impl_fromstr_literal_codec!(f64, "f64");
874
875fn type_term(name: &str) -> String {
876 format!("{TYPE_TERM_PREFIX}{name}")
877}
878
879fn literal_prefix(type_name: &str) -> String {
880 format!("{LITERAL_TERM_PREFIX}{type_name}:")
881}
882
883fn literal_term(type_name: &str, value: &str) -> String {
884 format!("{}{value}", literal_prefix(type_name))
885}
886
887fn invalid_literal(
888 object: LinkId,
889 type_name: &str,
890 value: Option<String>,
891 reason: &str,
892) -> LinksCodecError {
893 LinksCodecError::InvalidLiteral {
894 object,
895 type_name: type_name.to_string(),
896 value,
897 reason: reason.to_string(),
898 }
899}