1use crate::{
2 config::is_builtin_type_name,
3 load::ModuleLoader,
4 model::{
5 annotations::{
6 Annotation, AnnotationBuilder, AnnotationOnlyBody, AnnotationProperty, HasAnnotations,
7 },
8 check::{find_definition, validate_multiple_method_duplicates, MaybeIncomplete, Validate},
9 definitions::HasMultiMembers,
10 identifiers::{Identifier, IdentifierReference},
11 members::Member,
12 modules::Module,
13 values::Value,
14 HasName, HasOptionalBody, HasSourceSpan, References, Span,
15 },
16 store::ModuleStore,
17};
18use sdml_errors::diagnostics::functions::{
19 dimension_parent_not_entity, source_entity_missing_member, source_entity_not_entity,
20 type_definition_not_found, IdentifierCaseConvention,
21};
22use std::{
23 collections::{BTreeMap, BTreeSet},
24 fmt::Debug,
25};
26
27#[cfg(feature = "serde")]
28use serde::{Deserialize, Serialize};
29
30#[derive(Clone, Debug)]
36#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
37pub struct DimensionDef {
38 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
39 span: Option<Span>,
40 name: Identifier,
41 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
42 body: Option<DimensionBody>,
43}
44
45#[derive(Clone, Debug)]
47#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
48pub struct DimensionBody {
49 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
50 span: Option<Span>,
51 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
52 annotations: Vec<Annotation>,
53 identity: DimensionIdentity,
54 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "BTreeMap::is_empty"))]
55 parents: BTreeMap<Identifier, DimensionParent>,
56 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "BTreeMap::is_empty"))]
57 members: BTreeMap<Identifier, Member>,
58}
59
60#[derive(Clone, Debug)]
62#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
63pub enum DimensionIdentity {
64 Source(SourceEntity),
65 Identity(Member),
66}
67
68#[derive(Clone, Debug)]
70#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
71pub struct DimensionParent {
72 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
73 span: Option<Span>,
74 name: Identifier,
75 target_entity: IdentifierReference,
76 body: Option<AnnotationOnlyBody>,
77}
78
79#[derive(Clone, Debug)]
81#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
82pub struct SourceEntity {
83 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
84 span: Option<Span>,
85 target_entity: IdentifierReference,
86 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
87 with_members: Vec<Identifier>,
88}
89
90impl HasName for DimensionDef {
95 fn name(&self) -> &Identifier {
96 &self.name
97 }
98
99 fn set_name(&mut self, name: Identifier) {
100 self.name = name;
101 }
102}
103
104impl HasOptionalBody for DimensionDef {
105 type Body = DimensionBody;
106
107 fn body(&self) -> Option<&Self::Body> {
108 self.body.as_ref()
109 }
110
111 fn body_mut(&mut self) -> Option<&mut Self::Body> {
112 self.body.as_mut()
113 }
114
115 fn set_body(&mut self, body: Self::Body) {
116 self.body = Some(body);
117 }
118
119 fn unset_body(&mut self) {
120 self.body = None;
121 }
122}
123
124impl HasSourceSpan for DimensionDef {
125 fn with_source_span(self, span: Span) -> Self {
126 let mut self_mut = self;
127 self_mut.span = Some(span);
128 self_mut
129 }
130
131 fn source_span(&self) -> Option<&Span> {
132 self.span.as_ref()
133 }
134
135 fn set_source_span(&mut self, span: Span) {
136 self.span = Some(span);
137 }
138
139 fn unset_source_span(&mut self) {
140 self.span = None;
141 }
142}
143
144impl References for DimensionDef {
145 fn referenced_annotations<'a>(
146 &'a self,
147 names: &mut ::std::collections::BTreeSet<&'a IdentifierReference>,
148 ) {
149 if let Some(inner) = &self.body {
150 inner.referenced_annotations(names);
151 }
152 }
153
154 fn referenced_types<'a>(
155 &'a self,
156 names: &mut ::std::collections::BTreeSet<&'a IdentifierReference>,
157 ) {
158 if let Some(inner) = &self.body {
159 inner.referenced_types(names);
160 }
161 }
162}
163
164impl AnnotationBuilder for DimensionDef {
165 fn with_predicate<I, V>(self, predicate: I, value: V) -> Self
166 where
167 Self: Sized,
168 I: Into<IdentifierReference>,
169 V: Into<Value>,
170 {
171 let mut self_mut = self;
172 if let Some(ref mut inner) = self_mut.body {
173 inner.add_to_annotations(AnnotationProperty::new(predicate.into(), value.into()));
174 }
175 self_mut
176 }
177}
178
179impl MaybeIncomplete for DimensionDef {
180 fn is_incomplete(&self, top: &Module, cache: &impl ModuleStore) -> bool {
181 if let Some(body) = &self.body {
182 body.is_incomplete(top, cache)
183 } else {
184 true
185 }
186 }
187}
188
189impl Validate for DimensionDef {
190 fn validate(
191 &self,
192 top: &Module,
193 cache: &impl ModuleStore,
194 loader: &impl ModuleLoader,
195 check_constraints: bool,
196 ) {
197 self.name
198 .validate(top, loader, Some(IdentifierCaseConvention::TypeDefinition));
199 if let Some(body) = &self.body {
200 body.validate(top, cache, loader, check_constraints);
201 }
202 }
203}
204
205impl DimensionDef {
206 pub fn new(name: Identifier) -> Self {
211 Self {
212 span: None,
213 name,
214 body: None,
215 }
216 }
217
218 pub fn with_body(self, body: DimensionBody) -> Self {
219 let mut self_mut = self;
220 self_mut.body = Some(body);
221 self_mut
222 }
223}
224
225impl HasAnnotations for DimensionBody {
230 fn has_annotations(&self) -> bool {
231 !self.annotations.is_empty()
232 }
233
234 fn annotation_count(&self) -> usize {
235 self.annotations.len()
236 }
237
238 fn annotations(&self) -> impl Iterator<Item = &Annotation> {
239 self.annotations.iter()
240 }
241
242 fn annotations_mut(&mut self) -> impl Iterator<Item = &mut Annotation> {
243 self.annotations.iter_mut()
244 }
245
246 fn add_to_annotations<I>(&mut self, value: I)
247 where
248 I: Into<Annotation>,
249 {
250 self.annotations.push(value.into())
251 }
252
253 fn extend_annotations<I>(&mut self, extension: I)
254 where
255 I: IntoIterator<Item = Annotation>,
256 {
257 self.annotations.extend(extension)
258 }
259}
260
261impl HasSourceSpan for DimensionBody {
262 fn with_source_span(self, span: Span) -> Self {
263 let mut self_mut = self;
264 self_mut.span = Some(span);
265 self_mut
266 }
267
268 fn source_span(&self) -> Option<&Span> {
269 self.span.as_ref()
270 }
271
272 fn set_source_span(&mut self, span: Span) {
273 self.span = Some(span);
274 }
275
276 fn unset_source_span(&mut self) {
277 self.span = None;
278 }
279}
280
281impl MaybeIncomplete for DimensionBody {
282 fn is_incomplete(&self, top: &Module, cache: &impl ModuleStore) -> bool {
283 self.identity().is_incomplete(top, cache)
284 || self.members().any(|elem| elem.is_incomplete(top, cache))
285 }
286}
287
288impl Validate for DimensionBody {
289 fn validate(
290 &self,
291 top: &Module,
292 cache: &impl ModuleStore,
293 loader: &impl ModuleLoader,
294 check_constraints: bool,
295 ) {
296 validate_multiple_method_duplicates(self, top, cache, loader);
297
298 self.identity()
299 .validate(top, cache, loader, check_constraints);
300 self.annotations()
301 .for_each(|m| m.validate(top, cache, loader, check_constraints));
302 self.parents()
303 .for_each(|m| m.validate(top, cache, loader, check_constraints));
304 self.members()
305 .for_each(|m| m.validate(top, cache, loader, check_constraints));
306 }
307}
308
309impl References for DimensionBody {
310 fn referenced_types<'a>(&'a self, names: &mut BTreeSet<&'a IdentifierReference>) {
311 self.identity().referenced_types(names);
312 self.parents().for_each(|m| m.referenced_types(names));
313 self.members().for_each(|m| m.referenced_types(names));
314 }
315
316 fn referenced_annotations<'a>(&'a self, names: &mut BTreeSet<&'a IdentifierReference>) {
317 self.members().for_each(|m| m.referenced_annotations(names));
318 }
319}
320
321impl HasMultiMembers for DimensionBody {
322 fn has_any_members(&self) -> bool {
323 !(self.has_identity() || self.has_parents() || self.has_members())
324 }
325
326 fn contains_any_member(&self, name: &Identifier) -> bool {
327 self.contains_identity(name) || self.contains_parent(name) || self.contains_member(name)
328 }
329
330 fn all_member_count(&self) -> usize {
331 self.identity_count() + self.parent_count() + self.members.len()
332 }
333
334 fn all_member_names(&self) -> impl Iterator<Item = &Identifier> {
335 self.identity_names()
336 .chain(self.parent_names().chain(self.member_names()))
337 }
338}
339
340impl DimensionBody {
341 pub fn new<E>(entity: E) -> Self
346 where
347 E: Into<DimensionIdentity>,
348 {
349 Self {
350 span: Default::default(),
351 annotations: Default::default(),
352 identity: entity.into(),
353 parents: Default::default(),
354 members: Default::default(),
355 }
356 }
357
358 pub fn with_members<I>(self, members: I) -> Self
359 where
360 I: IntoIterator<Item = Member>,
361 {
362 let mut self_mut = self;
363 self_mut.members = members
364 .into_iter()
365 .map(|mem| (mem.name().clone(), mem))
366 .collect();
367 self_mut
368 }
369
370 pub fn with_parents<I>(self, parents: I) -> Self
371 where
372 I: IntoIterator<Item = DimensionParent>,
373 {
374 let mut self_mut = self;
375 self_mut.parents = parents
376 .into_iter()
377 .map(|mem| (mem.name().clone(), mem))
378 .collect();
379 self_mut
380 }
381
382 pub const fn identity(&self) -> &DimensionIdentity {
387 &self.identity
388 }
389
390 pub fn set_identity<T>(&mut self, identity: T)
391 where
392 T: Into<DimensionIdentity>,
393 {
394 self.identity = identity.into();
395 }
396
397 fn has_identity(&self) -> bool {
398 matches!(self.identity, DimensionIdentity::Identity(_))
399 }
400
401 fn identity_count(&self) -> usize {
402 match self.identity() {
403 DimensionIdentity::Source(src) => src.member_count(),
404 DimensionIdentity::Identity(_) => 1,
405 }
406 }
407
408 fn identity_names<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Identifier> + 'a> {
409 match self.identity() {
410 DimensionIdentity::Source(src) => Box::new(src.members()),
411 DimensionIdentity::Identity(id) => Box::new(std::iter::once(id.name())),
412 }
413 }
414
415 fn contains_identity(&self, name: &Identifier) -> bool {
416 match self.identity() {
417 DimensionIdentity::Source(src) => src.contains_member(name),
418 DimensionIdentity::Identity(id) => name == id.name(),
419 }
420 }
421
422 pub fn has_members(&self) -> bool {
427 !self.members.is_empty()
428 }
429
430 pub fn member_count(&self) -> usize {
431 self.members.len()
432 }
433
434 pub fn contains_member(&self, name: &Identifier) -> bool {
435 self.members.contains_key(name)
436 }
437
438 pub fn member(&self, name: &Identifier) -> Option<&Member> {
439 self.members.get(name)
440 }
441
442 pub fn member_mut(&mut self, name: &Identifier) -> Option<&mut Member> {
443 self.members.get_mut(name)
444 }
445
446 pub fn members(&self) -> impl Iterator<Item = &Member> {
447 self.members.values()
448 }
449
450 pub fn members_mut(&mut self) -> impl Iterator<Item = &mut Member> {
451 self.members.values_mut()
452 }
453
454 pub fn member_names(&self) -> impl Iterator<Item = &Identifier> {
455 self.members.keys()
456 }
457
458 pub fn add_to_members(&mut self, value: Member) -> Option<Member> {
459 self.members.insert(value.name().clone(), value)
460 }
461
462 pub fn extend_member<I>(&mut self, extension: I)
463 where
464 I: IntoIterator<Item = Member>,
465 {
466 self.members.extend(
467 extension
468 .into_iter()
469 .map(|elem| (elem.name().clone(), elem)),
470 )
471 }
472
473 pub fn has_parents(&self) -> bool {
478 !self.parents.is_empty()
479 }
480
481 pub fn parent_count(&self) -> usize {
482 self.parents.len()
483 }
484
485 pub fn contains_parent(&self, name: &Identifier) -> bool {
486 self.parents.contains_key(name)
487 }
488
489 pub fn parent(&self, name: &Identifier) -> Option<&DimensionParent> {
490 self.parents.get(name)
491 }
492
493 pub fn parent_mut(&mut self, name: &Identifier) -> Option<&mut DimensionParent> {
494 self.parents.get_mut(name)
495 }
496
497 pub fn parents(&self) -> impl Iterator<Item = &DimensionParent> {
498 self.parents.values()
499 }
500
501 pub fn parents_mut(&mut self) -> impl Iterator<Item = &mut DimensionParent> {
502 self.parents.values_mut()
503 }
504
505 pub fn parent_names(&self) -> impl Iterator<Item = &Identifier> {
506 self.parents.keys()
507 }
508
509 pub fn add_to_parents(&mut self, value: DimensionParent) -> Option<DimensionParent> {
510 self.parents.insert(value.name().clone(), value)
511 }
512
513 pub fn extend_parents<I>(&mut self, extension: I)
514 where
515 I: IntoIterator<Item = DimensionParent>,
516 {
517 self.parents.extend(
518 extension
519 .into_iter()
520 .map(|elem| (elem.name().clone(), elem)),
521 )
522 }
523}
524
525impl From<SourceEntity> for DimensionIdentity {
530 fn from(value: SourceEntity) -> Self {
531 Self::Source(value)
532 }
533}
534
535impl From<&SourceEntity> for DimensionIdentity {
536 fn from(value: &SourceEntity) -> Self {
537 Self::Source(value.clone())
538 }
539}
540
541impl From<Member> for DimensionIdentity {
542 fn from(value: Member) -> Self {
543 Self::Identity(value)
544 }
545}
546
547impl From<&Member> for DimensionIdentity {
548 fn from(value: &Member) -> Self {
549 Self::Identity(value.clone())
550 }
551}
552
553impl References for DimensionIdentity {
554 fn referenced_types<'a>(&'a self, names: &mut BTreeSet<&'a IdentifierReference>) {
555 match self {
556 DimensionIdentity::Source(v) => v.referenced_types(names),
557 DimensionIdentity::Identity(v) => v.referenced_types(names),
558 }
559 }
560}
561
562impl MaybeIncomplete for DimensionIdentity {
563 fn is_incomplete(&self, top: &Module, cache: &impl ModuleStore) -> bool {
564 match self {
565 Self::Source(_) => false,
566 Self::Identity(member) => member.is_incomplete(top, cache),
567 }
568 }
569}
570
571impl Validate for DimensionIdentity {
572 fn validate(
573 &self,
574 top: &Module,
575 cache: &impl ModuleStore,
576 loader: &impl ModuleLoader,
577 check_constraints: bool,
578 ) {
579 match self {
580 Self::Source(src) => src.validate(top, cache, loader, check_constraints),
581 Self::Identity(member) => member.validate(top, cache, loader, check_constraints),
582 }
583 }
584}
585
586impl DimensionIdentity {
587 pub const fn is_source_entity(&self) -> bool {
592 matches!(self, Self::Source(_))
593 }
594
595 pub const fn as_source_entity(&self) -> Option<&SourceEntity> {
596 match self {
597 Self::Source(v) => Some(v),
598 _ => None,
599 }
600 }
601
602 pub const fn is_identity_member(&self) -> bool {
603 matches!(self, Self::Identity(_))
604 }
605
606 pub const fn as_identity_member(&self) -> Option<&Member> {
607 match self {
608 Self::Identity(v) => Some(v),
609 _ => None,
610 }
611 }
612}
613
614impl HasName for DimensionParent {
619 fn name(&self) -> &Identifier {
620 &self.name
621 }
622
623 fn set_name(&mut self, name: Identifier) {
624 self.name = name;
625 }
626}
627
628impl HasSourceSpan for DimensionParent {
629 fn with_source_span(self, span: Span) -> Self {
630 let mut self_mut = self;
631 self_mut.span = Some(span);
632 self_mut
633 }
634
635 fn source_span(&self) -> Option<&Span> {
636 self.span.as_ref()
637 }
638
639 fn set_source_span(&mut self, span: Span) {
640 self.span = Some(span);
641 }
642
643 fn unset_source_span(&mut self) {
644 self.span = None;
645 }
646}
647
648impl HasOptionalBody for DimensionParent {
649 type Body = AnnotationOnlyBody;
650
651 fn body(&self) -> Option<&Self::Body> {
652 self.body.as_ref()
653 }
654
655 fn body_mut(&mut self) -> Option<&mut Self::Body> {
656 self.body.as_mut()
657 }
658
659 fn set_body(&mut self, body: Self::Body) {
660 self.body = Some(body);
661 }
662
663 fn unset_body(&mut self) {
664 self.body = None;
665 }
666}
667
668impl References for DimensionParent {
669 fn referenced_types<'a>(&'a self, names: &mut BTreeSet<&'a IdentifierReference>) {
670 names.insert(self.target_entity());
671 }
672}
673
674impl Validate for DimensionParent {
675 fn validate(
676 &self,
677 top: &Module,
678 cache: &impl ModuleStore,
679 loader: &impl ModuleLoader,
680 _: bool,
681 ) {
682 let name = self.target_entity();
683 if let Some(defn) = find_definition(name, top, cache) {
684 if !defn.is_entity() {
685 loader
686 .report(&dimension_parent_not_entity(
687 top.file_id().copied().unwrap_or_default(),
688 name.source_span().as_ref().map(|span| (*span).into()),
689 name,
690 ))
691 .unwrap();
692 }
693 } else if !name
694 .as_identifier()
695 .map(is_builtin_type_name)
696 .unwrap_or_default()
697 {
698 loader
699 .report(&type_definition_not_found(
700 top.file_id().copied().unwrap_or_default(),
701 name.source_span().as_ref().map(|span| (*span).into()),
702 name,
703 ))
704 .unwrap();
705 } else {
706 loader
707 .report(&dimension_parent_not_entity(
708 top.file_id().copied().unwrap_or_default(),
709 name.source_span().as_ref().map(|span| (*span).into()),
710 name,
711 ))
712 .unwrap();
713 }
714 }
715}
716
717impl DimensionParent {
718 pub fn new<I>(name: Identifier, target_entity: I) -> Self
723 where
724 I: Into<IdentifierReference>,
725 {
726 Self {
727 span: Default::default(),
728 name,
729 target_entity: target_entity.into(),
730 body: Default::default(),
731 }
732 }
733
734 pub fn with_body(self, body: AnnotationOnlyBody) -> Self {
735 let mut self_mut = self;
736 self_mut.body = Some(body);
737 self_mut
738 }
739
740 pub const fn target_entity(&self) -> &IdentifierReference {
745 &self.target_entity
746 }
747
748 pub fn set_target_entity<T>(&mut self, target_entity: T)
749 where
750 T: Into<IdentifierReference>,
751 {
752 self.target_entity = target_entity.into();
753 }
754}
755
756impl From<IdentifierReference> for SourceEntity {
761 fn from(value: IdentifierReference) -> Self {
762 Self::new(value)
763 }
764}
765
766impl From<&IdentifierReference> for SourceEntity {
767 fn from(value: &IdentifierReference) -> Self {
768 Self::new(value.clone())
769 }
770}
771
772impl HasSourceSpan for SourceEntity {
773 fn with_source_span(self, span: Span) -> Self {
774 let mut self_mut = self;
775 self_mut.span = Some(span);
776 self_mut
777 }
778
779 fn source_span(&self) -> Option<&Span> {
780 self.span.as_ref()
781 }
782
783 fn set_source_span(&mut self, span: Span) {
784 self.span = Some(span);
785 }
786
787 fn unset_source_span(&mut self) {
788 self.span = None;
789 }
790}
791
792impl Validate for SourceEntity {
793 fn validate(
794 &self,
795 top: &Module,
796 cache: &impl ModuleStore,
797 loader: &impl ModuleLoader,
798 _check_constraints: bool,
799 ) {
800 let name = self.target_entity();
801 if let Some(defn) = find_definition(name, top, cache) {
802 if let Some(entity) = defn.as_entity() {
803 match (self.has_members(), entity.body()) {
804 (true, Some(body)) => {
805 for member in self.members() {
806 if !body.contains_member(member) {
807 loader
808 .report(&source_entity_missing_member(
809 top.file_id().copied().unwrap_or_default(),
810 name.source_span().as_ref().map(|span| (*span).into()),
811 name,
812 ))
813 .unwrap();
814 }
815 }
816 }
817 (true, None) => {
818 for name in self.members() {
819 loader
820 .report(&source_entity_missing_member(
821 top.file_id().copied().unwrap_or_default(),
822 name.source_span().as_ref().map(|span| (*span).into()),
823 name,
824 ))
825 .unwrap();
826 }
827 }
828 (false, _) => (),
829 }
830 } else {
831 loader
832 .report(&source_entity_not_entity(
833 top.file_id().copied().unwrap_or_default(),
834 name.source_span().as_ref().map(|span| (*span).into()),
835 name,
836 ))
837 .unwrap();
838 }
839 } else if !name
840 .as_identifier()
841 .map(is_builtin_type_name)
842 .unwrap_or_default()
843 {
844 loader
845 .report(&type_definition_not_found(
846 top.file_id().copied().unwrap_or_default(),
847 name.source_span().as_ref().map(|span| (*span).into()),
848 name,
849 ))
850 .unwrap();
851 } else {
852 loader
853 .report(&source_entity_not_entity(
854 top.file_id().copied().unwrap_or_default(),
855 name.source_span().as_ref().map(|span| (*span).into()),
856 name,
857 ))
858 .unwrap();
859 }
860 }
861}
862
863impl References for SourceEntity {
864 fn referenced_types<'a>(&'a self, names: &mut BTreeSet<&'a IdentifierReference>) {
865 names.insert(self.target_entity());
866 }
867}
868
869impl SourceEntity {
870 pub fn new<T>(target_entity: T) -> Self
875 where
876 T: Into<IdentifierReference>,
877 {
878 Self {
879 span: Default::default(),
880 target_entity: target_entity.into(),
881 with_members: Default::default(),
882 }
883 }
884
885 pub fn with_members<I>(self, members: I) -> Self
886 where
887 I: IntoIterator<Item = Identifier>,
888 {
889 let mut self_mut = self;
890 self_mut.with_members = members.into_iter().collect();
891 self_mut
892 }
893
894 pub const fn target_entity(&self) -> &IdentifierReference {
899 &self.target_entity
900 }
901
902 pub fn set_target_entity<T>(&mut self, target_entity: T)
903 where
904 T: Into<IdentifierReference>,
905 {
906 self.target_entity = target_entity.into();
907 }
908
909 pub fn has_members(&self) -> bool {
912 !self.with_members.is_empty()
913 }
914
915 pub fn member_count(&self) -> usize {
916 self.with_members.len()
917 }
918
919 pub fn contains_member(&self, name: &Identifier) -> bool {
920 self.members().any(|n| n == name)
921 }
922
923 pub fn members(&self) -> impl Iterator<Item = &Identifier> {
924 self.with_members.iter()
925 }
926
927 pub fn members_mut(&mut self) -> impl Iterator<Item = &mut Identifier> {
928 self.with_members.iter_mut()
929 }
930
931 pub fn add_to_members<I>(&mut self, value: I)
932 where
933 I: Into<Identifier>,
934 {
935 self.with_members.push(value.into())
936 }
937
938 pub fn extend_members<I>(&mut self, extension: I)
939 where
940 I: IntoIterator<Item = Identifier>,
941 {
942 self.with_members.extend(extension)
943 }
944}