# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

class SlotsMetaclass(type):
  """This metaclass requires all subclasses to define __slots__.

  Usage:
    class Foo(object):
      __metaclass__ = slots_metaclass.SlotsMetaclass
      __slots__ = '_property0', '_property1',

  __slots__ must be a tuple containing string names of all properties that the
  class contains.
  Defining __slots__ reduces memory usage, accelerates property access, and
  prevents dynamically adding unlisted properties.
  If you need to dynamically add unlisted properties to a class with this
  metaclass, then take a step back and rethink your goals. If you really really
  need to dynamically add unlisted properties to a class with this metaclass,
  add '__dict__' to its __slots__.
  """

  def __new__(mcs, name, bases, attrs):
    assert '__slots__' in attrs, 'Class "%s" must define __slots__' % name
    assert isinstance(attrs['__slots__'], tuple), '__slots__ must be a tuple'

    return super(SlotsMetaclass, mcs).__new__(mcs, name, bases, attrs)
