rust/hg-cpython/src/ref_sharing.rs
author Martin von Zweigbergk <martinvonz@google.com>
Tue, 18 May 2021 21:50:09 -0700
changeset 47306 dd339191f2dc
parent 44297 6b7aef44274b
permissions -rw-r--r--
errors: make StorageError subclass Error, attaching an exit code to it Differential Revision: https://phab.mercurial-scm.org/D10741
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
43082
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
     1
// ref_sharing.rs
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     2
//
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     3
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     4
//
43082
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
     5
// Permission is hereby granted, free of charge, to any person obtaining a copy
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
     6
// of this software and associated documentation files (the "Software"), to
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
     7
// deal in the Software without restriction, including without limitation the
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
     8
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
     9
// sell copies of the Software, and to permit persons to whom the Software is
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    10
// furnished to do so, subject to the following conditions:
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    11
//
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    12
// The above copyright notice and this permission notice shall be included in
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    13
// all copies or substantial portions of the Software.
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    14
//
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    15
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    16
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    17
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    18
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    19
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    20
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
diff changeset
    21
// IN THE SOFTWARE.
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    22
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    23
//! Macros for use in the `hg-cpython` bridge library.
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    24
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    25
/// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    26
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    27
/// TODO: this is a bit awkward to use, and a better (more complicated)
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    28
///     procedural macro would simplify the interface a lot.
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    29
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    30
/// # Parameters
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    31
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    32
/// * `$name` is the identifier to give to the resulting Rust struct.
44297
6b7aef44274b rust-cpython: remove PySharedRefCell and its companion structs
Yuya Nishihara <yuya@tcha.org>
parents: 44282
diff changeset
    33
/// * `$leaked` corresponds to `UnsafePyLeaked` in the matching `@shared data`
6b7aef44274b rust-cpython: remove PySharedRefCell and its companion structs
Yuya Nishihara <yuya@tcha.org>
parents: 44282
diff changeset
    34
/// declaration.
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    35
/// * `$iterator_type` is the type of the Rust iterator.
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    36
/// * `$success_func` is a function for processing the Rust `(key, value)`
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    37
/// tuple on iteration success, turning it into something Python understands.
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    38
/// * `$success_func` is the return type of `$success_func`
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    39
///
44282
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44281
diff changeset
    40
/// # Safety
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44281
diff changeset
    41
///
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44281
diff changeset
    42
/// `$success_func` may take a reference, but it's lifetime may be cheated.
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44281
diff changeset
    43
/// Do not copy it out of the function call.
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44281
diff changeset
    44
///
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    45
/// # Example
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    46
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    47
/// ```
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    48
/// struct MyStruct {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    49
///     inner: HashMap<Vec<u8>, Vec<u8>>;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    50
/// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    51
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    52
/// py_class!(pub class MyType |py| {
44297
6b7aef44274b rust-cpython: remove PySharedRefCell and its companion structs
Yuya Nishihara <yuya@tcha.org>
parents: 44282
diff changeset
    53
///     @shared data inner: MyStruct;
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    54
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    55
///     def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
43482
8418b77132c1 rust-cpython: remove useless PyResult<> from leak_immutable()
Yuya Nishihara <yuya@tcha.org>
parents: 43481
diff changeset
    56
///         let leaked_ref = self.inner_shared(py).leak_immutable();
42897
5ccc08d02280 rust-cpython: leverage py_shared_iterator::from_inner() where appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 42896
diff changeset
    57
///         MyTypeItemsIterator::from_inner(
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    58
///             py,
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
    59
///             unsafe { leaked_ref.map(py, |o| o.iter()) },
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    60
///         )
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    61
///     }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    62
/// });
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    63
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    64
/// impl MyType {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    65
///     fn translate_key_value(
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    66
///         py: Python,
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    67
///         res: (&Vec<u8>, &Vec<u8>),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    68
///     ) -> PyResult<Option<(PyBytes, PyBytes)>> {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    69
///         let (f, entry) = res;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    70
///         Ok(Some((
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    71
///             PyBytes::new(py, f),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    72
///             PyBytes::new(py, entry),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    73
///         )))
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    74
///     }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    75
/// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    76
///
42895
ea91a126c803 rust-cpython: rename py_shared_iterator_impl to py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42894
diff changeset
    77
/// py_shared_iterator!(
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    78
///     MyTypeItemsIterator,
44297
6b7aef44274b rust-cpython: remove PySharedRefCell and its companion structs
Yuya Nishihara <yuya@tcha.org>
parents: 44282
diff changeset
    79
///     UnsafePyLeaked<HashMap<'static, Vec<u8>, Vec<u8>>>,
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    80
///     MyType::translate_key_value,
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    81
///     Option<(PyBytes, PyBytes)>
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    82
/// );
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
    83
/// ```
42895
ea91a126c803 rust-cpython: rename py_shared_iterator_impl to py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42894
diff changeset
    84
macro_rules! py_shared_iterator {
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    85
    (
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    86
        $name: ident,
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
    87
        $leaked: ty,
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    88
        $success_func: expr,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    89
        $success_type: ty
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    90
    ) => {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    91
        py_class!(pub class $name |py| {
43478
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43477
diff changeset
    92
            data inner: RefCell<$leaked>;
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    93
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    94
            def __next__(&self) -> PyResult<$success_type> {
43478
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43477
diff changeset
    95
                let mut leaked = self.inner(py).borrow_mut();
44282
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44281
diff changeset
    96
                let mut iter = unsafe { leaked.try_borrow_mut(py)? };
43478
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43477
diff changeset
    97
                match iter.next() {
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43477
diff changeset
    98
                    None => Ok(None),
44282
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44281
diff changeset
    99
                    // res may be a reference of cheated 'static lifetime
43478
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43477
diff changeset
   100
                    Some(res) => $success_func(py, res),
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   101
                }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   102
            }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   103
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   104
            def __iter__(&self) -> PyResult<Self> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   105
                Ok(self.clone_ref(py))
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   106
            }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   107
        });
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   108
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   109
        impl $name {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   110
            pub fn from_inner(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   111
                py: Python,
42896
74d67c645278 rust-cpython: remove Option<_> from interface of py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42895
diff changeset
   112
                leaked: $leaked,
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   113
            ) -> PyResult<Self> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   114
                Self::create_instance(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   115
                    py,
43478
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43477
diff changeset
   116
                    RefCell::new(leaked),
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   117
                )
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   118
            }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   119
        }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   120
    };
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   121
}