1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 module thrift.internal.traits; 20 21 import std.traits; 22 23 /** 24 * Adds or removes attributes from the given function (pointer) or delegate 25 * type. 26 * 27 * Besides the base type, two std.traits.FunctionAttribute bitfields are 28 * accepted, representing the attributes to add to the function signature 29 * resp. to remove from it. If an attribute appears in both fields, an error 30 * is raised. 31 * 32 * Params: 33 * T = The base type. 34 * setAttrs = The attributes to add to the type, if not already present. 35 * clearAttrs = The attributes to remove from the type, if present. 36 */ 37 template ChangeFuncAttrs( 38 T, 39 FunctionAttribute setAttrs = FunctionAttribute.none, 40 FunctionAttribute clearAttrs = FunctionAttribute.none 41 ) if (isFunctionPointer!T || isDelegate!T) { 42 static assert(!(setAttrs & clearAttrs), 43 "Cannot set and clear attributes at the same time."); 44 mixin({ 45 enum newAttrs = (functionAttributes!T | setAttrs) & ~clearAttrs; 46 static assert(!(newAttrs & FunctionAttribute.trusted) || 47 !(newAttrs & FunctionAttribute.safe), 48 "Cannot have a function/delegate that is both trusted and safe."); 49 50 string result = "alias "; 51 52 static if (functionLinkage!T != "D") { 53 result ~= "extern(" ~ functionLinkage!T ~ ") "; 54 } 55 56 static if (newAttrs & FunctionAttribute.ref_) { 57 result ~= "ref "; 58 } 59 60 result ~= "ReturnType!T"; 61 62 static if (isDelegate!T) { 63 result ~= " delegate"; 64 } else { 65 result ~= " function"; 66 } 67 68 result ~= "(ParameterTypeTuple!T)"; 69 70 static if (newAttrs & FunctionAttribute.pure_) { 71 result ~= " pure"; 72 } 73 static if (newAttrs & FunctionAttribute.nothrow_) { 74 result ~= " nothrow"; 75 } 76 static if (newAttrs & FunctionAttribute.property) { 77 result ~= " @property"; 78 } 79 static if (newAttrs & FunctionAttribute.trusted) { 80 result ~= " @trusted"; 81 } 82 static if (newAttrs & FunctionAttribute.safe) { 83 result ~= " @safe"; 84 } 85 86 result ~= " ChangeFuncAttrs;"; 87 return result; 88 }()); 89 } 90 91 /// Ditto 92 template ChangeFuncAttrs( 93 T, 94 FunctionAttribute setAttrs = FunctionAttribute.none, 95 FunctionAttribute clearAttrs = FunctionAttribute.none 96 ) if (is(T == function)) { 97 // To avoid a lot of syntactic headaches, we just use the above version to 98 // operate on the corresponding function pointer type and then remove the 99 // pointer again. 100 alias FunctionTypeOf!(ChangeFuncAttrs!(T*, setAttrs, clearAttrs)) 101 ChangeFuncAttrs; 102 } 103 104 version (unittest) { 105 import std.algorithm; 106 import std.metastrings; 107 import std.typetuple; 108 } 109 unittest { 110 alias FunctionAttribute FA; 111 foreach (T0; TypeTuple!( 112 int function(int), 113 int delegate(int), 114 FunctionTypeOf!(int function(int)) 115 )) { 116 alias ChangeFuncAttrs!(T0, FA.safe) T1; 117 static assert(functionAttributes!T1 == FA.safe); 118 119 alias ChangeFuncAttrs!(T1, FA.nothrow_ | FA.ref_, FA.safe) T2; 120 static assert(functionAttributes!T2 == (FA.nothrow_ | FA.ref_)); 121 122 enum allAttrs = reduce!"a | b"([EnumMembers!FA]) & ~FA.safe; 123 124 alias ChangeFuncAttrs!(T2, allAttrs) T3; 125 static assert(functionAttributes!T3 == allAttrs); 126 127 alias ChangeFuncAttrs!(T3, FA.none, allAttrs) T4; 128 static assert(is(T4 == T0)); 129 } 130 } 131 132 /** 133 * Adds »nothrow« to the type of the passed function pointer/delegate, if it 134 * is not already present. 135 * 136 * Technically, assumeNothrow just performs a cast, but using it has the 137 * advantage of being explicitly about the operation that is performed. 138 */ 139 auto assumeNothrow(T)(T t) if (isFunctionPointer!T || isDelegate!T) { 140 return cast(ChangeFuncAttrs!(T, FunctionAttribute.nothrow_))t; 141 }