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
use re_log_types::{hash::Hash64, EntityPath, EntityPathFilter, EntityPathSubs};
use re_types::SpaceViewClassIdentifier;

/// Properties of a space view that as recommended to be spawned by default via space view spawn heuristics.
#[derive(Debug, Clone)]
pub struct RecommendedSpaceView {
    pub origin: EntityPath,
    pub query_filter: EntityPathFilter,
}

/// Heuristics for spawning space views of a given class.
///
/// Provides information in order to decide whether to spawn a space views, putting them in relationship to others and spawning them.
// TODO(andreas): allow bucketing decisions for 0-n buckets for recommended space views.
// TODO(andreas): Should `SpaceViewClassLayoutPriority` be part of this struct?
#[derive(Default)]
pub struct SpaceViewSpawnHeuristics {
    /// The recommended space views to spawn
    recommended_space_views: Vec<RecommendedSpaceView>,
}

impl SpaceViewSpawnHeuristics {
    #[inline]
    pub fn empty() -> Self {
        Self {
            recommended_space_views: Vec::new(),
        }
    }

    #[inline]
    pub fn root() -> Self {
        Self {
            recommended_space_views: vec![RecommendedSpaceView::root()],
        }
    }

    pub fn new(iter: impl IntoIterator<Item = RecommendedSpaceView>) -> Self {
        let mut recommended_space_views: Vec<RecommendedSpaceView> = iter.into_iter().collect();
        recommended_space_views.sort_by(|a, b| a.origin.cmp(&b.origin));
        Self {
            recommended_space_views,
        }
    }

    #[inline]
    pub fn into_vec(self) -> Vec<RecommendedSpaceView> {
        self.recommended_space_views
    }
}

impl RecommendedSpaceView {
    #[inline]
    pub fn new<'a>(origin: EntityPath, expressions: impl IntoIterator<Item = &'a str>) -> Self {
        let space_env = EntityPathSubs::new_with_origin(&origin);
        Self {
            origin,
            query_filter: EntityPathFilter::from_query_expressions_forgiving(
                expressions,
                &space_env,
            ),
        }
    }

    #[inline]
    pub fn new_subtree(origin: EntityPath) -> Self {
        Self::new(origin, std::iter::once("$origin/**"))
    }

    #[inline]
    pub fn new_single_entity(origin: EntityPath) -> Self {
        Self::new(origin, std::iter::once("$origin"))
    }

    #[inline]
    pub fn root() -> Self {
        Self::new_subtree(EntityPath::root())
    }

    /// Hash together with the Space View class id to the `ViewerRecommendationHash` component.
    ///
    /// Recommendations are usually tied to a specific Space View class.
    /// Therefore, to identify a recommendation for identification purposes, the class id should be included in the hash.
    pub fn recommendation_hash(
        &self,
        class_id: SpaceViewClassIdentifier,
    ) -> re_types::blueprint::components::ViewerRecommendationHash {
        let Self {
            origin,
            query_filter,
        } = self;

        Hash64::hash((origin, query_filter, class_id))
            .hash64()
            .into()
    }
}