1# -*- test-case-name: foolscap.test.test_banana -*-
2
3from twisted.python.components import registerAdapter
4from twisted.internet.defer import Deferred
5from foolscap import tokens
6from foolscap.tokens import Violation, BananaError
7from foolscap.slicer import BaseSlicer, LeafUnslicer
8from foolscap.constraint import OpenerConstraint, IntegerConstraint, Any
9
10class BooleanSlicer(BaseSlicer):
11    opentype = ('boolean',)
12    trackReferences = False
13    def sliceBody(self, streamable, banana):
14        if self.obj:
15            yield 1
16        else:
17            yield 0
18registerAdapter(BooleanSlicer, bool, tokens.ISlicer)
19
20class BooleanUnslicer(LeafUnslicer):
21    opentype = ('boolean',)
22
23    value = None
24    constraint = None
25
26    def setConstraint(self, constraint):
27        if isinstance(constraint, Any):
28            return
29        assert isinstance(constraint, BooleanConstraint)
30        self.constraint = constraint
31
32    def checkToken(self, typebyte, size):
33        if typebyte != tokens.INT:
34            raise BananaError("BooleanUnslicer only accepts an INT token")
35        if self.value != None:
36            raise BananaError("BooleanUnslicer only accepts one token")
37
38    def receiveChild(self, obj, ready_deferred=None):
39        assert not isinstance(obj, Deferred)
40        assert ready_deferred is None
41        assert type(obj) == int
42        if self.constraint:
43            if self.constraint.value != None:
44                if bool(obj) != self.constraint.value:
45                    raise Violation("This boolean can only be %s" % \
46                                    self.constraint.value)
47        self.value = bool(obj)
48
49    def receiveClose(self):
50        return self.value, None
51
52    def describe(self):
53        return "<bool>"
54
55class BooleanConstraint(OpenerConstraint):
56    strictTaster = True
57    opentypes = [("boolean",)]
58    _myint = IntegerConstraint()
59    name = "BooleanConstraint"
60
61    def __init__(self, value=None):
62        # self.value is a joke. This allows you to use a schema of
63        # BooleanConstraint(True) which only accepts 'True'. I cannot
64        # imagine a possible use for this, but it made me laugh.
65        self.value = value
66
67    def checkObject(self, obj, inbound):
68        if type(obj) != bool:
69            raise Violation("not a bool")
70        if self.value != None:
71            if obj != self.value:
72                raise Violation("not %s" % self.value)
73