• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Starlark helpers for Objective-C protos."""
2
3# State constants for objc_proto_camel_case_name.
4_last_was_other = 0
5_last_was_lowercase = 1
6_last_was_uppercase = 2
7_last_was_number = 3
8
9def objc_proto_camel_case_name(name):
10    """A Starlark version of the ObjC generator's CamelCase name transform.
11
12    This needs to track
13    src/google/protobuf/compiler/objectivec/names.cc's UnderscoresToCamelCase()
14
15    NOTE: This code is written to model the C++ in protoc's ObjC generator so it
16    is easier to confirm that the algorithms between the implementations match.
17    The customizations for starlark performance are:
18    - The cascade within the loop is reordered and special cases "_" to
19      optimize for google3 inputs.
20    - The "last was" state is handled via integers instead of three booleans.
21
22    The `first_capitalized` argument in the C++ code is left off this code and
23    it acts as if the value were `True`.
24
25    Args:
26      name: The proto file name to convert to camel case. The extension should
27        already be removed.
28
29    Returns:
30      The converted proto name to camel case.
31    """
32    segments = []
33    current = ""
34    last_was = _last_was_other
35    for c in name.elems():
36        if c.islower():
37            # lowercase letter can follow a lowercase or uppercase letter.
38            if last_was != _last_was_lowercase and last_was != _last_was_uppercase:
39                segments.append(current)
40                current = c.upper()
41            else:
42                current += c
43            last_was = _last_was_lowercase
44        elif c == "_":  # more common than rest, special case it.
45            last_was = _last_was_other
46        elif c.isdigit():
47            if last_was != _last_was_number:
48                segments.append(current)
49                current = ""
50            current += c
51            last_was = _last_was_number
52        elif c.isupper():
53            if last_was != _last_was_uppercase:
54                segments.append(current)
55                current = c
56            else:
57                current += c.lower()
58            last_was = _last_was_uppercase
59        else:
60            last_was = _last_was_other
61    segments.append(current)
62    result = ""
63    for x in segments:
64        if x in ("Url", "Http", "Https"):
65            result += x.upper()
66        else:
67            result += x
68    return result
69