1use core::fmt;
2
3use crate::{
4 entity::{EntityProjection, EntityProjectionMut},
5 Block, BlockRef, EntityCursor, EntityCursorMut, EntityMut, EntityRef, Operation, OperationRef,
6 Spanned,
7};
8
9#[derive(Default, Copy, Clone)]
19pub enum ProgramPoint {
20 #[default]
22 Invalid,
23 Block {
25 block: BlockRef,
27 position: Position,
29 },
30 Op {
32 op: OperationRef,
34 position: Position,
36 },
37}
38
39#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
41pub enum Position {
42 Before,
44 After,
46}
47
48impl<T> From<EntityRef<'_, T>> for ProgramPoint
49where
50 for<'a> ProgramPoint: From<&'a T>,
51{
52 #[inline]
53 fn from(entity: EntityRef<'_, T>) -> Self {
54 Self::from(&*entity)
55 }
56}
57
58impl<T> From<EntityMut<'_, T>> for ProgramPoint
59where
60 for<'a> ProgramPoint: From<&'a T>,
61{
62 #[inline]
63 fn from(entity: EntityMut<'_, T>) -> Self {
64 Self::from(&*entity)
65 }
66}
67
68impl From<&Operation> for ProgramPoint {
70 #[inline]
71 fn from(op: &Operation) -> Self {
72 Self::from(op.as_operation_ref())
73 }
74}
75
76impl From<OperationRef> for ProgramPoint {
78 #[inline]
79 fn from(op: OperationRef) -> Self {
80 Self::Op {
81 op,
82 position: Position::Before,
83 }
84 }
85}
86
87impl From<&Block> for ProgramPoint {
89 #[inline]
90 fn from(block: &Block) -> Self {
91 Self::at_start_of(block.as_block_ref())
92 }
93}
94
95impl From<BlockRef> for ProgramPoint {
97 #[inline]
98 fn from(block: BlockRef) -> Self {
99 Self::Block {
100 block,
101 position: Position::Before,
102 }
103 }
104}
105
106#[doc(hidden)]
107#[derive(Copy, Clone)]
108pub struct BlockPoint {
109 block: BlockRef,
110 point: Position,
111}
112impl From<BlockPoint> for ProgramPoint {
113 fn from(point: BlockPoint) -> Self {
114 ProgramPoint::Block {
115 block: point.block,
116 position: point.point,
117 }
118 }
119}
120impl From<BlockRef> for BlockPoint {
121 fn from(block: BlockRef) -> Self {
122 Self {
123 block,
124 point: Position::Before,
125 }
126 }
127}
128impl From<&Block> for BlockPoint {
129 fn from(block: &Block) -> Self {
130 Self {
131 block: block.as_block_ref(),
132 point: Position::Before,
133 }
134 }
135}
136
137impl ProgramPoint {
138 #[inline]
140 pub fn before(entity: impl Into<ProgramPoint>) -> Self {
141 entity.into()
142 }
143
144 pub fn after(entity: impl Into<ProgramPoint>) -> Self {
146 let mut pp = entity.into();
147 match &mut pp {
148 Self::Invalid => (),
149 Self::Op {
150 position: ref mut point,
151 ..
152 }
153 | Self::Block {
154 position: ref mut point,
155 ..
156 } => {
157 *point = Position::After;
158 }
159 }
160 pp
161 }
162
163 pub fn at_start_of(block: impl Into<BlockPoint>) -> Self {
165 let BlockPoint { block, .. } = block.into();
166 Self::Block {
167 block,
168 position: Position::Before,
169 }
170 }
171
172 pub fn at_end_of(block: impl Into<BlockPoint>) -> Self {
174 let BlockPoint { block, .. } = block.into();
175 Self::Block {
176 block,
177 position: Position::After,
178 }
179 }
180
181 pub fn is_at_block_start(&self) -> bool {
183 self.operation().is_some_and(|op| {
184 op.parent().is_some() && op.prev().is_none() && self.placement() == Position::Before
185 }) || matches!(self, Self::Block { position: Position::Before, block, .. } if block.borrow().body().is_empty())
186 }
187
188 pub fn is_at_block_end(&self) -> bool {
190 self.operation().is_some_and(|op| {
191 op.parent().is_some() && op.next().is_none() && self.placement() == Position::After
192 }) || matches!(self, Self::Block { position: Position::After, block, .. } if block.borrow().body().is_empty())
193 }
194
195 pub fn block(&self) -> Option<BlockRef> {
199 match self {
200 Self::Invalid => None,
201 Self::Block { block, .. } => Some(*block),
202 Self::Op { op, .. } => op.parent(),
203 }
204 }
205
206 pub fn operation(&self) -> Option<OperationRef> {
210 match self {
211 Self::Invalid => None,
212 Self::Block {
213 position: Position::Before,
214 block,
215 ..
216 } => block.borrow().body().front().as_pointer(),
217 Self::Block {
218 position: Position::After,
219 block,
220 ..
221 } => block.borrow().body().back().as_pointer(),
222 Self::Op { op, .. } => Some(*op),
223 }
224 }
225
226 #[track_caller]
232 pub fn next_operation(&self) -> Option<OperationRef> {
233 assert!(!self.is_at_block_end());
234 match self {
235 Self::Op {
236 position: Position::After,
237 op,
238 ..
239 } if op.parent().is_some() => op.next(),
240 Self::Op { op, .. } => Some(*op),
241 Self::Block {
242 position: Position::Before,
243 block,
244 } => block.borrow().front(),
245 Self::Block { .. } | Self::Invalid => None,
246 }
247 }
248
249 #[track_caller]
255 pub fn prev_operation(&self) -> Option<OperationRef> {
256 assert!(!self.is_at_block_start());
257 match self {
258 Self::Op {
259 position: Position::Before,
260 op,
261 ..
262 } if op.parent().is_some() => op.prev(),
263 Self::Op { op, .. } => Some(*op),
264 Self::Block {
265 position: Position::After,
266 block,
267 } => block.borrow().back(),
268 Self::Block { .. } | Self::Invalid => None,
269 }
270 }
271
272 #[inline]
274 pub fn is_valid(&self) -> bool {
275 !self.is_unset()
276 }
277
278 #[inline]
280 pub fn is_unset(&self) -> bool {
281 matches!(self, Self::Invalid)
282 }
283
284 pub fn placement(&self) -> Position {
286 match self {
287 Self::Invalid => Position::After,
288 Self::Block {
289 position: point, ..
290 }
291 | Self::Op {
292 position: point, ..
293 } => *point,
294 }
295 }
296
297 pub fn cursor<'a, 'b: 'a, 'c: 'b>(
319 &'c self,
320 ) -> Option<EntityProjection<'b, EntityCursor<'a, Operation>>> {
321 match self {
322 Self::Invalid => None,
323 Self::Block {
324 block,
325 position: point,
326 } => Some(EntityRef::project(block.borrow(), |block| match point {
327 Position::Before => block.body().front(),
328 Position::After => block.body().back(),
329 })),
330 Self::Op {
331 op,
332 position: point,
333 } => {
334 let block = op.parent()?;
335 Some(EntityRef::project(block.borrow(), |block| match point {
336 Position::Before => {
337 if let Some(placement) = op.prev() {
338 unsafe { block.body().cursor_from_ptr(placement) }
339 } else {
340 block.body().cursor()
341 }
342 }
343 Position::After => unsafe { block.body().cursor_from_ptr(*op) },
344 }))
345 }
346 }
347 }
348
349 pub fn cursor_mut<'a, 'b: 'a, 'c: 'b>(
354 &'c mut self,
355 ) -> Option<EntityProjectionMut<'b, EntityCursorMut<'a, Operation>>> {
356 match self {
357 Self::Invalid => None,
358 Self::Block {
359 block,
360 position: point,
361 } => Some(EntityMut::project(block.borrow_mut(), |block| match point {
362 Position::Before => block.body_mut().cursor_mut(),
363 Position::After => block.body_mut().back_mut(),
364 })),
365 Self::Op {
366 op,
367 position: point,
368 } => {
369 let mut block = op.parent()?;
370 Some(EntityMut::project(block.borrow_mut(), |block| match point {
371 Position::Before => {
372 if let Some(placement) = op.prev() {
373 unsafe { block.body_mut().cursor_mut_from_ptr(placement) }
374 } else {
375 block.body_mut().cursor_mut()
376 }
377 }
378 Position::After => unsafe { block.body_mut().cursor_mut_from_ptr(*op) },
379 }))
380 }
381 }
382 }
383}
384
385impl Eq for ProgramPoint {}
386
387impl PartialEq for ProgramPoint {
388 fn eq(&self, other: &Self) -> bool {
389 match (self, other) {
390 (Self::Invalid, Self::Invalid) => true,
391 (Self::Invalid, _) | (_, Self::Invalid) => false,
392 (
393 Self::Block {
394 block: x,
395 position: xp,
396 },
397 Self::Block {
398 block: y,
399 position: yp,
400 },
401 ) => x == y && xp == yp,
402 (
403 Self::Op {
404 op: x,
405 position: xp,
406 ..
407 },
408 Self::Op {
409 op: y,
410 position: yp,
411 ..
412 },
413 ) => x == y && xp == yp,
414 (..) => false,
415 }
416 }
417}
418
419impl core::hash::Hash for ProgramPoint {
420 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
421 core::mem::discriminant(self).hash(state);
422 match self {
423 Self::Invalid => (),
424 Self::Block {
425 block,
426 position: point,
427 } => {
428 core::ptr::hash(BlockRef::as_ptr(block), state);
429 point.hash(state);
430 }
431 Self::Op {
432 op,
433 position: point,
434 ..
435 } => {
436 core::ptr::hash(OperationRef::as_ptr(op), state);
437 point.hash(state);
438 }
439 }
440 }
441}
442
443impl Spanned for ProgramPoint {
444 fn span(&self) -> crate::SourceSpan {
445 use crate::SourceSpan;
446
447 match self {
448 Self::Invalid => SourceSpan::UNKNOWN,
449 Self::Block {
450 block,
451 position: point,
452 } => match point {
453 Position::Before => {
454 block.borrow().body().front().get().map(|op| op.span()).unwrap_or_default()
455 }
456 Position::After => {
457 block.borrow().body().back().get().map(|op| op.span()).unwrap_or_default()
458 }
459 },
460 Self::Op { op, .. } => op.borrow().span(),
461 }
462 }
463}
464
465impl fmt::Display for ProgramPoint {
466 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
467 use crate::EntityWithId;
468 match self {
469 Self::Invalid => f.write_str("<invalid>"),
470 Self::Block {
471 block,
472 position: point,
473 } => match point {
474 Position::Before => write!(f, "start({})", &block.borrow().id()),
475 Position::After => write!(f, "end({})", &block.borrow().id()),
476 },
477 Self::Op {
478 op,
479 position: point,
480 } => {
481 use crate::formatter::{const_text, display};
482 let block = op
483 .parent()
484 .map(|blk| display(blk.borrow().id()))
485 .unwrap_or_else(|| const_text("null"));
486 match point {
487 Position::Before => {
488 write!(f, "before({} in {block})", &op.borrow().name())
489 }
490 Position::After => {
491 write!(f, "after({} in {block})", &op.borrow().name())
492 }
493 }
494 }
495 }
496 }
497}
498
499impl fmt::Debug for ProgramPoint {
500 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
501 use crate::EntityWithId;
502 match self {
503 Self::Invalid => f.write_str("Invalid"),
504 Self::Block {
505 block,
506 position: point,
507 } => f
508 .debug_struct("Block")
509 .field("block", &block.borrow().id())
510 .field("point", point)
511 .finish(),
512 Self::Op {
513 op,
514 position: point,
515 } => f
516 .debug_struct("Op")
517 .field("block", &op.parent().map(|blk| blk.borrow().id()))
518 .field("point", point)
519 .field("op", &op.borrow())
520 .finish(),
521 }
522 }
523}