summaryrefslogtreecommitdiffstats
path: root/toolkit/components/bitsdownload/src/bits_interface/task/from_threadbound.rs
blob: 2cf2e9189ab966d6b68757ae8c9fb1c1fe6cf3cc (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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::{
    action::Action,
    error::{BitsTaskError, ErrorStage, ErrorType},
};
use log::warn;
use xpcom::{RefCounted, ThreadBoundRefPtr};

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum DataType {
    Callback,
    BitsService,
    BitsRequest,
    Observer,
    Context,
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum GetThreadboundError {
    Missing,
    WrongThread,
}

impl DataType {
    fn error_type(&self, error: GetThreadboundError) -> ErrorType {
        match self {
            DataType::Callback => match error {
                GetThreadboundError::Missing => ErrorType::MissingCallback,
                GetThreadboundError::WrongThread => ErrorType::CallbackOnWrongThread,
            },
            DataType::BitsService => match error {
                GetThreadboundError::Missing => ErrorType::MissingBitsService,
                GetThreadboundError::WrongThread => ErrorType::BitsServiceOnWrongThread,
            },
            DataType::BitsRequest => match error {
                GetThreadboundError::Missing => ErrorType::MissingBitsRequest,
                GetThreadboundError::WrongThread => ErrorType::BitsRequestOnWrongThread,
            },
            DataType::Observer => match error {
                GetThreadboundError::Missing => ErrorType::MissingObserver,
                GetThreadboundError::WrongThread => ErrorType::ObserverOnWrongThread,
            },
            DataType::Context => match error {
                GetThreadboundError::Missing => ErrorType::MissingContext,
                GetThreadboundError::WrongThread => ErrorType::ContextOnWrongThread,
            },
        }
    }

    fn name(&self) -> &'static str {
        match self {
            DataType::Callback => "Callback",
            DataType::BitsService => "BITS Service",
            DataType::BitsRequest => "BITS Request",
            DataType::Observer => "Observer",
            DataType::Context => "Context",
        }
    }
}

/// Given a reference to a threadbound option
/// (i.e. `&Option<ThreadBoundRefPtr<_>>`), this function will attempt to
/// retrieve a reference to the value stored within. If it is not available
/// (option is `None` or value is on the wrong thread), `None` is returned
/// instead.
pub fn get_from_threadbound_option<T>(
    maybe_threadbound: &Option<ThreadBoundRefPtr<T>>,
    data_type: DataType,
    action: Action,
) -> Option<&T>
where
    T: RefCounted + 'static,
{
    maybe_threadbound.as_ref().and_then(|threadbound| {
        let maybe_reference = threadbound.get_ref();
        if maybe_reference.is_none() {
            warn!(
                "Unexpected error {}: {} is on the wrong thread",
                action.description(),
                data_type.name(),
            );
        }
        maybe_reference
    })
}

/// Given a reference to a threadbound option
/// (i.e. `&Option<ThreadBoundRefPtr<_>>`), this function will attempt to
/// retrieve a reference to the value stored within. If it is not available
/// (option is `None` or value is on the wrong thread), a `BitsTaskError` is
/// returned instead.
pub fn expect_from_threadbound_option<T>(
    maybe_threadbound: &Option<ThreadBoundRefPtr<T>>,
    data_type: DataType,
    action: Action,
) -> Result<&T, BitsTaskError>
where
    T: RefCounted + 'static,
{
    match maybe_threadbound.as_ref() {
        Some(threadbound) => {
            match threadbound.get_ref() {
                Some(reference) => Ok(reference),
                None => Err(BitsTaskError::new(
                    data_type.error_type(GetThreadboundError::WrongThread),
                    action,
                    // Retrieving data from threadbounds all happens on the main thread.
                    // No data is ever bound to other threads so there would be no
                    // reason to retrieve it there.
                    ErrorStage::MainThread,
                )),
            }
        }
        None => Err(BitsTaskError::new(
            data_type.error_type(GetThreadboundError::Missing),
            action,
            // Retrieving data from threadbounds all happens on the main thread.
            // No data is ever bound to other threads so there would be no
            // reason to retrieve it there.
            ErrorStage::MainThread,
        )),
    }
}