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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Take a look at the license at the top of the repository in the LICENSE file.

use std::marker::PhantomData;

use glib::{object::IsClass, prelude::*, Object, Type};

use crate::{prelude::*, Cancellable, Initable};

impl Initable {
    // rustdoc-stripper-ignore-next
    /// Create a new instance of an object with the default property values.
    ///
    /// Similar to [`Object::new`] but can fail because the object initialization in
    /// `Initable::init` failed.
    // rustdoc-stripper-ignore-next-stop
    /// Helper function for constructing [`Initable`][crate::Initable] object. This is
    /// similar to [`glib::Object::new()`][crate::glib::Object::new()] but also initializes the object
    /// and returns [`None`], setting an error on failure.
    /// ## `object_type`
    /// a `GType` supporting [`Initable`][crate::Initable].
    /// ## `cancellable`
    /// optional [`Cancellable`][crate::Cancellable] object, [`None`] to ignore.
    /// ## `first_property_name`
    /// the name of the first property, or [`None`] if no
    ///  properties
    ///
    /// # Returns
    ///
    /// a newly allocated
    ///  [`glib::Object`][crate::glib::Object], or [`None`] on error
    #[track_caller]
    #[allow(clippy::new_ret_no_self)]
    pub fn new<T: IsA<Object> + IsClass + IsA<Initable>>(
        cancellable: Option<&impl IsA<Cancellable>>,
    ) -> Result<T, glib::Error> {
        let object = Self::with_type(T::static_type(), cancellable)?;
        Ok(unsafe { object.unsafe_cast() })
    }

    // rustdoc-stripper-ignore-next
    /// Create a new instance of an object with the default property values.
    ///
    /// Similar to [`Object::with_type`] but can fail because the object initialization in
    /// `Initable::init` failed.
    #[track_caller]
    pub fn with_type(
        type_: Type,
        cancellable: Option<&impl IsA<Cancellable>>,
    ) -> Result<Object, glib::Error> {
        if !type_.is_a(Initable::static_type()) {
            panic!("Type '{type_}' is not initable");
        }

        unsafe {
            let object = Object::new_internal(type_, &mut []);
            object.unsafe_cast_ref::<Self>().init(cancellable)?;
            Ok(object)
        }
    }

    // rustdoc-stripper-ignore-next
    /// Create a new instance of an object of the given type with the given properties as mutable
    /// values.
    ///
    /// # Panics
    ///
    /// This panics if the object is not instantiable, doesn't have all the given properties or
    /// property values of the wrong type are provided.
    #[track_caller]
    pub fn with_mut_values(
        type_: Type,
        properties: &mut [(&str, glib::Value)],
        cancellable: Option<&impl IsA<Cancellable>>,
    ) -> Result<Object, glib::Error> {
        if !type_.is_a(Initable::static_type()) {
            panic!("Type '{type_}' is not initable");
        }

        unsafe {
            let object = Object::new_internal(type_, properties);
            object.unsafe_cast_ref::<Self>().init(cancellable)?;
            Ok(object)
        }
    }

    // rustdoc-stripper-ignore-next
    /// Create a new object builder for a specific type.
    pub fn builder<'a, O: IsA<Object> + IsClass + IsA<Initable>>() -> InitableBuilder<'a, O> {
        InitableBuilder::new(O::static_type())
    }

    // rustdoc-stripper-ignore-next
    /// Create a new object builder for a specific type.
    pub fn builder_with_type<'a>(type_: Type) -> InitableBuilder<'a, Object> {
        if !type_.is_a(Initable::static_type()) {
            panic!("Type '{type_}' is not initable");
        }

        InitableBuilder::new(type_)
    }
}

#[must_use = "builder doesn't do anything unless built"]
pub struct InitableBuilder<'a, O> {
    type_: Type,
    properties: smallvec::SmallVec<[(&'a str, glib::Value); 16]>,
    phantom: PhantomData<O>,
}

impl<'a, O: IsA<Object> + IsClass> InitableBuilder<'a, O> {
    #[inline]
    fn new(type_: Type) -> Self {
        InitableBuilder {
            type_,
            properties: smallvec::SmallVec::new(),
            phantom: PhantomData,
        }
    }

    // rustdoc-stripper-ignore-next
    /// Gets the type of this builder.
    #[inline]
    pub fn type_(&self) -> Type {
        self.type_
    }

    // rustdoc-stripper-ignore-next
    /// Set property `name` to the given value `value`.
    #[inline]
    pub fn property(self, name: &'a str, value: impl Into<glib::Value>) -> Self {
        let InitableBuilder {
            type_,
            mut properties,
            ..
        } = self;
        properties.push((name, value.into()));

        InitableBuilder {
            type_,
            properties,
            phantom: PhantomData,
        }
    }

    // rustdoc-stripper-ignore-next
    /// Build the object with the provided properties.
    ///
    /// # Panics
    ///
    /// This panics if the object is not instantiable, doesn't have all the given properties or
    /// property values of the wrong type are provided.
    #[track_caller]
    #[inline]
    pub fn build(mut self, cancellable: Option<&impl IsA<Cancellable>>) -> Result<O, glib::Error> {
        let object = Initable::with_mut_values(self.type_, &mut self.properties, cancellable)?;
        Ok(unsafe { object.unsafe_cast::<O>() })
    }
}