summaryrefslogtreecommitdiff
path: root/src/mask.ml
blob: 5179876106e5de013ef1de29a29795a25af9e0cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
open Diff

module Mask_inclusive = struct
    type t = { left: Config_tree.t;
               right: Config_tree.t;
             }

    let make_init l r = { left = l;
                          right = r;
                        }

    (* mask function; mask applied on right *)
    let diff_func ?descent:_ (path : string list) res (m : change) =
        (* alert exn Vytree.delete:
            [Vytree.Empty_path] not possible since Unchanged pattern is only empty path
            [Vytree.Nonexistent_path] not possible as called on existing config paths (res.left)
           alert exn Vytree.is_terminal_path:
            [Vytree.Empty_path] not possible since Unchanged pattern is only empty path
         *)
        match m with
        | Added -> res
        | Subtracted ->
            begin
                match path with
                | [_] ->
                    {res with left = (Vytree.delete[@alert "-exn"]) res.left path}
                |  _  ->
                    if not ((Vytree.is_terminal_path[@alert "-exn"]) res.right (Util.drop_last path)) then
                        {res with left = (Vytree.delete[@alert "-exn"]) res.left path}
                    else res
            end
        | Unchanged -> res
        | Updated _ -> res
end

module Mask_exclusive = struct
    type t = { left: Config_tree.t;
               right: Config_tree.t;
             }

    let make_init l r = { left = l;
                          right = r;
                        }

    (* mask function; mask applied on right *)
    let diff_func ?(descent=true) (path : string list) res (m : change) =
        (* alert exn Vytree.delete:
            [Vytree.Empty_path] not possible in pattern match case
            [Vytree.Nonexistent_path] not possible as called on existing config paths (res.left)
           alert exn Vytree.is_terminal_path:
            [Vytree.Empty_path] not possible in pattern match case
         *)
        match m with
        | Added -> res
        | Subtracted -> res
        | Unchanged | Updated _ ->
            begin
                match path with
                | [] ->
                    if descent then
                        (* in the diff function, descent = true on an empty path means that the
                           trees are equal, hence exclude all: return default (empty) tree *)
                        {res with left = Config_tree.default}
                    else res
                | _ ->
                    if descent || ((Vytree.is_terminal_path[@alert "-exn"]) res.right path) then
                        let tmp = (Vytree.delete[@alert "-exn"]) res.left path in
                        let left' = (Config_tree.prune_delete[@alert "-exn"]) tmp path in
                        {res with left = left'}
                    else res
            end
end

module MI = Diff(Mask_inclusive)

module ME = Diff(Mask_exclusive)

let mask_inclusive left right =
    (* raises:
        [Empty_comparison] from diff
        [Incommensurable]
     *)
    if (Vytree.name_of_node left) <> (Vytree.name_of_node right) then
        raise Incommensurable
    else
    let init = Mask_inclusive.make_init left right in
    let res = MI.diff init left right in
    res.left

let mask_exclusive left right =
    (* raises:
        [Empty_comparison] from diff
        [Incommensurable]
     *)
    if (Vytree.name_of_node left) <> (Vytree.name_of_node right) then
        raise Incommensurable
    else
    let init = Mask_exclusive.make_init left right in
    let res = ME.diff init left right in
    res.left