A better Rust ATProto crate
at main 145 lines 5.7 kB view raw
1use super::CodeGenerator; 2use crate::lexicon::{ 3 LexArrayItem, LexObjectProperty, LexPrimitiveArrayItem, LexString, LexStringFormat, 4 LexUserType, LexXrpcParametersProperty, 5}; 6 7/// Trait for lexicon types that can determine lifetime requirements 8trait HasLifetime { 9 /// Check if this type needs a lifetime parameter when generated 10 fn needs_lifetime(&self, generator: &CodeGenerator) -> bool; 11} 12 13impl HasLifetime for LexObjectProperty<'_> { 14 fn needs_lifetime(&self, generator: &CodeGenerator) -> bool { 15 match self { 16 LexObjectProperty::Boolean(_) | LexObjectProperty::Integer(_) => false, 17 LexObjectProperty::String(s) => s.needs_lifetime(generator), 18 LexObjectProperty::Bytes(_) => false, // Bytes is owned 19 LexObjectProperty::CidLink(_) 20 | LexObjectProperty::Blob(_) 21 | LexObjectProperty::Unknown(_) => true, 22 LexObjectProperty::Array(array) => array.items.needs_lifetime(generator), 23 LexObjectProperty::Object(_) => true, // Nested objects have lifetimes 24 LexObjectProperty::Ref(ref_type) => generator.ref_needs_lifetime(&ref_type.r#ref), 25 LexObjectProperty::Union(_) => true, // Unions generally have lifetimes 26 } 27 } 28} 29 30impl HasLifetime for LexArrayItem<'_> { 31 fn needs_lifetime(&self, generator: &CodeGenerator) -> bool { 32 match self { 33 LexArrayItem::Boolean(_) | LexArrayItem::Integer(_) => false, 34 LexArrayItem::String(s) => s.needs_lifetime(generator), 35 LexArrayItem::Bytes(_) => false, 36 LexArrayItem::CidLink(_) | LexArrayItem::Blob(_) | LexArrayItem::Unknown(_) => true, 37 LexArrayItem::Object(_) => true, // Nested objects have lifetimes 38 LexArrayItem::Ref(ref_type) => generator.ref_needs_lifetime(&ref_type.r#ref), 39 LexArrayItem::Union(_) => true, 40 } 41 } 42} 43 44impl HasLifetime for LexString<'_> { 45 fn needs_lifetime(&self, _generator: &CodeGenerator) -> bool { 46 match self.format { 47 Some(LexStringFormat::Datetime) 48 | Some(LexStringFormat::Language) 49 | Some(LexStringFormat::Tid) => false, 50 _ => true, // Most string types borrow 51 } 52 } 53} 54 55impl HasLifetime for LexUserType<'_> { 56 fn needs_lifetime(&self, generator: &CodeGenerator) -> bool { 57 match self { 58 LexUserType::Record(_) => true, 59 LexUserType::Object(_) => true, 60 LexUserType::Token(_) => false, 61 LexUserType::String(s) => { 62 // Check if it's a known values enum or a regular string 63 if s.known_values.is_some() { 64 // Known values enums have Other(CowStr<'a>) variant 65 true 66 } else { 67 s.needs_lifetime(generator) 68 } 69 } 70 LexUserType::Integer(_) => false, 71 LexUserType::Boolean(_) => false, 72 LexUserType::Bytes(_) => false, 73 LexUserType::CidLink(_) | LexUserType::Blob(_) | LexUserType::Unknown(_) => true, 74 LexUserType::Array(array) => array.items.needs_lifetime(generator), 75 LexUserType::XrpcQuery(_) 76 | LexUserType::XrpcProcedure(_) 77 | LexUserType::XrpcSubscription(_) => { 78 // XRPC types generate multiple structs, not a single type we can reference 79 // Shouldn't be referenced directly 80 true 81 } 82 LexUserType::Union(_) => true, // Union enums are always generated with <'a> 83 } 84 } 85} 86 87impl HasLifetime for LexXrpcParametersProperty<'_> { 88 fn needs_lifetime(&self, generator: &CodeGenerator) -> bool { 89 match self { 90 LexXrpcParametersProperty::Boolean(_) | LexXrpcParametersProperty::Integer(_) => false, 91 LexXrpcParametersProperty::String(s) => s.needs_lifetime(generator), 92 LexXrpcParametersProperty::Unknown(_) => true, 93 LexXrpcParametersProperty::Array(arr) => arr.items.needs_lifetime(generator), 94 } 95 } 96} 97 98impl HasLifetime for LexPrimitiveArrayItem<'_> { 99 fn needs_lifetime(&self, generator: &CodeGenerator) -> bool { 100 match self { 101 LexPrimitiveArrayItem::Boolean(_) | LexPrimitiveArrayItem::Integer(_) => false, 102 LexPrimitiveArrayItem::String(s) => s.needs_lifetime(generator), 103 LexPrimitiveArrayItem::Unknown(_) => true, 104 } 105 } 106} 107 108impl<'c> CodeGenerator<'c> { 109 /// Check if a property type needs a lifetime parameter 110 pub(super) fn property_needs_lifetime(&self, prop: &LexObjectProperty<'_>) -> bool { 111 prop.needs_lifetime(self) 112 } 113 114 /// Check if an array item type needs a lifetime parameter 115 pub(super) fn array_item_needs_lifetime(&self, item: &LexArrayItem<'_>) -> bool { 116 item.needs_lifetime(self) 117 } 118 119 /// Check if a string type needs a lifetime parameter 120 pub(super) fn string_needs_lifetime(&self, s: &LexString<'_>) -> bool { 121 s.needs_lifetime(self) 122 } 123 124 /// Check if a ref needs a lifetime parameter 125 pub(super) fn ref_needs_lifetime(&self, ref_str: &str) -> bool { 126 // Try to resolve the ref 127 if let Some((_doc, def)) = self.corpus.resolve_ref(ref_str) { 128 def.needs_lifetime(self) 129 } else { 130 // If we can't resolve it, assume it needs a lifetime (safe default) 131 true 132 } 133 } 134 135 /// Check if xrpc params need a lifetime parameter 136 pub(super) fn params_need_lifetime( 137 &self, 138 params: &crate::lexicon::LexXrpcParameters<'_>, 139 ) -> bool { 140 params 141 .properties 142 .values() 143 .any(|prop| prop.needs_lifetime(self)) 144 } 145}