|
| 1 | +package com.credimi.pandora.core.annotations |
| 2 | + |
| 3 | +import com.credimi.pandora.core |
| 4 | +import com.credimi.pandora.core.hash.HashFunction |
| 5 | +import com.credimi.pandora.core.path.Step |
| 6 | +import com.credimi.pandora.core.{ hash, ByteSerializable, Tree } |
| 7 | + |
| 8 | +case class Ids[A]( |
| 9 | + id: hash.Hash, |
| 10 | + parentId: Option[hash.Hash], |
| 11 | + nonListAncestor: Option[Ids.Ancestor], |
| 12 | + index: Option[Int], |
| 13 | + annotation: A |
| 14 | +) |
| 15 | + |
| 16 | +object Ids { |
| 17 | + |
| 18 | + case class Ancestor( |
| 19 | + path: core.path.Path, |
| 20 | + id: hash.Hash |
| 21 | + ) |
| 22 | + |
| 23 | + def endOfPath(path: core.path.Path): Option[Step] = |
| 24 | + path.steps.lastOption |
| 25 | + |
| 26 | + def nodeId(parentId: Option[hash.Hash], path: core.path.Path, nodeHash: hash.Hash)(implicit |
| 27 | + hashFunction: HashFunction |
| 28 | + ): hash.Hash = |
| 29 | + hashFunction( |
| 30 | + parentId.toArray.flatMap(_.bytes) ++ |
| 31 | + endOfPath(path).toArray.flatMap(implicitly[ByteSerializable[Step]].bytes) ++ |
| 32 | + nodeHash.bytes |
| 33 | + ) |
| 34 | + |
| 35 | + case class ParentData[A](annotation: Ids[Path[Hash[A]]], isList: Boolean) |
| 36 | + |
| 37 | + def ids[A, L](parentData: Option[ParentData[A]], annotation: Path[Hash[A]])(implicit |
| 38 | + hashFunction: HashFunction |
| 39 | + ): Ids[Path[Hash[A]]] = { |
| 40 | + val parentId: Option[hash.Hash] = parentData.map(_.annotation.id) |
| 41 | + val nonListParent: Option[Ancestor] = |
| 42 | + parentData.flatMap(parentData => |
| 43 | + if (!parentData.isList) Some(Ancestor(parentData.annotation.annotation.path, parentData.annotation.id)) |
| 44 | + else None |
| 45 | + ) |
| 46 | + val nonListAncestor: Option[Ancestor] = nonListParent orElse parentData.flatMap(_.annotation.nonListAncestor) |
| 47 | + val path = annotation.path |
| 48 | + val nodeHash = annotation.annotation.hash |
| 49 | + Ids( |
| 50 | + id = nodeId(parentId = parentId, path = path, nodeHash = nodeHash), |
| 51 | + parentId = parentId, |
| 52 | + nonListAncestor = nonListAncestor, |
| 53 | + index = endOfPath(path).flatMap { case Step.Index(index) => Some(index); case _ => None }, |
| 54 | + annotation = annotation |
| 55 | + ) |
| 56 | + } |
| 57 | + |
| 58 | + def ids[A, L]( |
| 59 | + parentData: Option[ParentData[A]] |
| 60 | + )(tree: Tree[Path[Hash[A]], L])(implicit hashFunction: HashFunction): Tree[Ids[Path[Hash[A]]], L] = |
| 61 | + tree match { |
| 62 | + case core.Leaf(annotation, leaf) => |
| 63 | + core.Leaf(annotation = ids(parentData, annotation), leaf = leaf) |
| 64 | + case core.List(annotation, list) => |
| 65 | + val nodeAnnotation = ids(parentData, annotation) |
| 66 | + core.List( |
| 67 | + annotation = nodeAnnotation, |
| 68 | + list = list.map(ids(Some(ParentData(annotation = nodeAnnotation, isList = true)))) |
| 69 | + ) |
| 70 | + case core.Dict(annotation, dict) => |
| 71 | + val nodeAnnotation = ids(parentData, annotation) |
| 72 | + core.Dict( |
| 73 | + annotation = nodeAnnotation, |
| 74 | + dict = dict.view.mapValues(ids(Some(ParentData[A](annotation = nodeAnnotation, isList = false)))).toMap |
| 75 | + ) |
| 76 | + } |
| 77 | + |
| 78 | + def ids[A, L](tree: Tree[Path[Hash[A]], L])(implicit hashFunction: HashFunction): Tree[Ids[Path[Hash[A]]], L] = |
| 79 | + ids(None)(tree) |
| 80 | + |
| 81 | +} |
0 commit comments