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

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

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

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

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

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

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

impl RecommendedView {
    #[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 View class id to the `ViewerRecommendationHash` component.
    ///
    /// Recommendations are usually tied to a specific 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: ViewClassIdentifier,
    ) -> re_types::blueprint::components::ViewerRecommendationHash {
        let Self {
            origin,
            query_filter,
        } = self;

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