1use std::{fmt, ops::ControlFlow, rc::Rc};23use jrsonnet_gcmodule::{Acyclic, Trace, TraceBox};4use jrsonnet_interner::IStr;5use jrsonnet_ir::Span;67use super::{8 CcObjectAssertion, EnumFields, EnumFieldsHandler, FieldVisibility, GetFor,9 HasFieldIncludeHidden, ObjFieldFlags, ObjectCore, SupThis, Visibility,10 ordering::{FieldIndex, SuperDepth},11};12use crate::{MaybeUnbound, Result};1314#[derive(Acyclic, Debug)]15pub struct ShapeField {16 pub name: IStr,17 pub flags: ObjFieldFlags,18 pub location: Option<Span>,19 pub index: FieldIndex,20}2122#[derive(Acyclic, Debug)]23pub struct ObjShape {24 fields: Vec<ShapeField>,25}2627impl ObjShape {28 #[must_use]29 pub fn new(fields: Vec<ShapeField>) -> Self {30 Self { fields }31 }3233 #[inline]34 pub fn fields(&self) -> &[ShapeField] {35 &self.fields36 }3738 #[inline]39 #[must_use]40 pub fn len(&self) -> usize {41 self.fields.len()42 }4344 #[inline]45 #[must_use]46 pub fn is_empty(&self) -> bool {47 self.fields.is_empty()48 }4950 #[inline]51 pub fn find_index(&self, name: &IStr) -> Option<usize> {52 self.fields.iter().position(|f| &f.name == name)53 }54}5556#[derive(Trace)]57pub struct StaticShapeOopObject {58 shape: Rc<ObjShape>,59 bindings: TraceBox<[MaybeUnbound]>,60 assertion: Option<CcObjectAssertion>,61}6263impl fmt::Debug for StaticShapeOopObject {64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {65 f.debug_struct("StaticShapeOopObject")66 .field("shape", &self.shape)67 .field("has_assertion", &self.assertion.is_some())68 .finish_non_exhaustive()69 }70}7172impl StaticShapeOopObject {73 pub fn new(74 shape: Rc<ObjShape>,75 bindings: Vec<MaybeUnbound>,76 assertion: Option<CcObjectAssertion>,77 ) -> Self {78 debug_assert_eq!(79 shape.fields.len(),80 bindings.len(),81 "shape arity must match bindings"82 );83 Self {84 shape,85 bindings: TraceBox(bindings.into_boxed_slice()),86 assertion,87 }88 }8990 #[inline]91 #[must_use]92 pub const fn shape(&self) -> &Rc<ObjShape> {93 &self.shape94 }95}9697impl ObjectCore for StaticShapeOopObject {98 fn enum_fields_core(99 &self,100 super_depth: &mut SuperDepth,101 handler: &mut EnumFieldsHandler<'_>,102 ) -> bool {103 for field in &self.shape.fields {104 if matches!(105 handler(106 *super_depth,107 field.index,108 field.name.clone(),109 EnumFields::Normal(field.flags.visibility()),110 ),111 ControlFlow::Break(())112 ) {113 return false;114 }115 }116 true117 }118119 fn has_field_include_hidden_core(&self, name: IStr) -> HasFieldIncludeHidden {120 if self.shape.find_index(&name).is_some() {121 HasFieldIncludeHidden::Exists122 } else {123 HasFieldIncludeHidden::NotFound124 }125 }126127 fn get_for_core(&self, key: IStr, sup_this: SupThis, omit_only: bool) -> Result<GetFor> {128 if omit_only {129 return Ok(GetFor::NotFound);130 }131 let Some(i) = self.shape.find_index(&key) else {132 return Ok(GetFor::NotFound);133 };134 let field = &self.shape.fields[i];135 let v = self.bindings[i].evaluate(sup_this)?;136 Ok(if field.flags.add() {137 GetFor::SuperPlus(v)138 } else {139 GetFor::Final(v)140 })141 }142143 fn field_visibility_core(&self, field: IStr) -> FieldVisibility {144 self.shape145 .find_index(&field)146 .map_or(FieldVisibility::NotFound, |i| {147 FieldVisibility::Found(self.shape.fields[i].flags.visibility())148 })149 }150151 fn run_assertions_core(&self, sup_this: SupThis) -> Result<()> {152 if let Some(assertion) = &self.assertion {153 assertion.0.run(sup_this)?;154 }155 Ok(())156 }157158 fn has_assertion(&self) -> bool {159 self.assertion.is_some()160 }161}162163pub struct ObjShapeBuilder {164 fields: Vec<ShapeField>,165 next_index: FieldIndex,166}167168impl ObjShapeBuilder {169 #[must_use]170 pub fn new() -> Self {171 Self {172 fields: Vec::new(),173 next_index: FieldIndex::default(),174 }175 }176177 #[must_use]178 pub fn with_capacity(cap: usize) -> Self {179 Self {180 fields: Vec::with_capacity(cap),181 next_index: FieldIndex::default(),182 }183 }184185 pub fn field(186 &mut self,187 name: impl Into<IStr>,188 visibility: Visibility,189 add: bool,190 location: Option<Span>,191 ) -> &mut Self {192 let index = self.next_index;193 self.next_index = self.next_index.next();194 self.fields.push(ShapeField {195 name: name.into(),196 flags: ObjFieldFlags::new(add, visibility),197 location,198 index,199 });200 self201 }202203 #[must_use]204 pub fn build(self) -> ObjShape {205 ObjShape::new(self.fields)206 }207}208209impl Default for ObjShapeBuilder {210 fn default() -> Self {211 Self::new()212 }213}